@firestone-hs/simulate-bgs-battle 1.1.749 → 1.1.750
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/cards/card.interface.d.ts +4 -0
- package/dist/cards/card.interface.js +4 -2
- package/dist/cards/card.interface.js.map +1 -1
- package/dist/cards/impl/enchantments/deaths-embrace.d.ts +2 -2
- package/dist/cards/impl/enchantments/deaths-embrace.js +5 -5
- package/dist/cards/impl/enchantments/deaths-embrace.js.map +1 -1
- package/dist/cards/impl/trinket/all-purpose-kibble.js +1 -1
- package/dist/cards/impl/trinket/all-purpose-kibble.js.map +1 -1
- package/dist/cards/impl/trinket/herald-sticker.js +4 -1
- package/dist/cards/impl/trinket/herald-sticker.js.map +1 -1
- package/dist/cards/impl/trinket/training-certificate.js +5 -2
- package/dist/cards/impl/trinket/training-certificate.js.map +1 -1
- package/dist/simulate-bgs-battle.d.ts +2 -2
- package/dist/simulate-bgs-battle.js +14 -13
- package/dist/simulate-bgs-battle.js.map +1 -1
- package/dist/simulation/deathrattle-on-trigger.js +2 -2
- package/dist/simulation/deathrattle-on-trigger.js.map +1 -1
- package/dist/simulation/start-of-combat/soc-illidan-hero-power.js.map +1 -1
- package/package.json +1 -1
|
@@ -172,6 +172,10 @@ export interface DeathrattleTriggeredCard extends Card {
|
|
|
172
172
|
onDeathrattleTriggered(minion: BoardEntity | BoardTrinket | BoardEnchantment, input: DeathrattleTriggeredInput): void;
|
|
173
173
|
}
|
|
174
174
|
export declare const hasOnDeathrattleTriggered: (card: Card) => card is DeathrattleTriggeredCard;
|
|
175
|
+
export interface DeathrattleTriggeredEnchantmentCard extends Card {
|
|
176
|
+
onDeathrattleTriggeredEnchantment(enchantedMinion: BoardEntity, enchantment: BoardEnchantment, input: DeathrattleTriggeredInput): void;
|
|
177
|
+
}
|
|
178
|
+
export declare const hasOnDeathrattleTriggeredEnchantment: (card: Card) => card is DeathrattleTriggeredEnchantmentCard;
|
|
175
179
|
export interface DeathrattleSpawnEnchantmentCard extends Card {
|
|
176
180
|
deathrattleSpawnEnchantmentEffect(enchantment: BoardEnchantment, minion: BoardEntity | null | undefined, input: DeathrattleTriggeredInput): readonly BoardEntity[];
|
|
177
181
|
cardIds: readonly string[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.hasOnGilded = exports.hasOnGlobalInfoUpdatedEnchantment = exports.hasOnGlobalInfoUpdated = exports.hasPlayedBloodGemsOnAny = exports.hasPlayedBloodGemsOnMe = exports.hasOnSpawnFail = exports.hasOnAfterMagnetize = exports.hasOnAfterMagnetizeSelf = exports.hasOnAfterMagnetizeToSelf = exports.hasOnBeforeMagnetizeSelf = exports.hasOnBeforeMagnetize = void 0;
|
|
3
|
+
exports.hasOnAfterFriendlyMinionDeath = exports.hasOnAfterDeath = exports.hasOnDeath = exports.hasAfterFriendlyMinionDamagedTrinket = exports.hasAfterDealDamage = exports.hasOnDamaged = exports.hasAfterHeroDamaged = exports.hasOnStatsChanged = exports.hasOnWindfuryUpdated = exports.hasOnVenomousUpdated = exports.hasOnStealthUpdated = exports.hasOnRebornUpdated = exports.hasOnTauntUpdated = exports.hasOnDivineShieldUpdated = exports.hasEndOfTurn = exports.hasOnCardAddedToHand = exports.hasDeathrattleSpawnEnchantment = exports.hasOnDeathrattleTriggeredEnchantment = exports.hasOnDeathrattleTriggered = exports.hasDefaultScriptDataNum = exports.hasAvenge = exports.hasOnBattlecryTriggered = exports.hasAfterReborn = exports.hasRebornSelfAttributeTransfer = exports.hasBeforeRebornSelfEffect = exports.hasRebornSelfEffect = exports.hasRebornEffect = exports.hasBattlecry = exports.hasDeathrattleEffect = exports.hasDeathrattleSpawn = exports.hasOnDespawnedEnchantment = exports.OnDespawnedEnchantmentCard = exports.hasOnDespawned = exports.hasOnFriendlyMinionSummonedTrinket = exports.hasAfterOtherSpawned = exports.hasOnOtherSpawned = exports.hasOnOtherAuraSpawned = exports.hasOnSpawnedEnchantment = exports.hasOnSpawned = exports.hasOnMinionAttacked = exports.hasAfterAnotherMinionAttacks = exports.hasOnWheneverAnotherMinionAttacks = exports.hasRally = exports.hasAfterTavernSpellCast = exports.hasOnBeforeTavernSpellCast = exports.hasOnTavernSpellCast = exports.hasCastTavernSpell = exports.hasStartOfCombatFromHand = exports.hasStartOfCombat = exports.hasDefaultCharges = void 0;
|
|
4
|
+
exports.hasOnGilded = exports.hasOnGlobalInfoUpdatedEnchantment = exports.hasOnGlobalInfoUpdated = exports.hasPlayedBloodGemsOnAny = exports.hasPlayedBloodGemsOnMe = exports.hasOnSpawnFail = exports.hasOnAfterMagnetize = exports.hasOnAfterMagnetizeSelf = exports.hasOnAfterMagnetizeToSelf = exports.hasOnBeforeMagnetizeSelf = exports.hasOnBeforeMagnetize = exports.hasOnMinionKilled = void 0;
|
|
5
5
|
const hasDefaultCharges = (card) => (card === null || card === void 0 ? void 0 : card.defaultCharges) !== undefined;
|
|
6
6
|
exports.hasDefaultCharges = hasDefaultCharges;
|
|
7
7
|
const hasStartOfCombat = (card) => (card === null || card === void 0 ? void 0 : card.startOfCombat) !== undefined;
|
|
@@ -66,6 +66,8 @@ const hasDefaultScriptDataNum = (card) => (card === null || card === void 0 ? vo
|
|
|
66
66
|
exports.hasDefaultScriptDataNum = hasDefaultScriptDataNum;
|
|
67
67
|
const hasOnDeathrattleTriggered = (card) => (card === null || card === void 0 ? void 0 : card.onDeathrattleTriggered) !== undefined;
|
|
68
68
|
exports.hasOnDeathrattleTriggered = hasOnDeathrattleTriggered;
|
|
69
|
+
const hasOnDeathrattleTriggeredEnchantment = (card) => (card === null || card === void 0 ? void 0 : card.onDeathrattleTriggeredEnchantment) !== undefined;
|
|
70
|
+
exports.hasOnDeathrattleTriggeredEnchantment = hasOnDeathrattleTriggeredEnchantment;
|
|
69
71
|
const hasDeathrattleSpawnEnchantment = (card) => (card === null || card === void 0 ? void 0 : card.deathrattleSpawnEnchantmentEffect) !== undefined;
|
|
70
72
|
exports.hasDeathrattleSpawnEnchantment = hasDeathrattleSpawnEnchantment;
|
|
71
73
|
const hasOnCardAddedToHand = (card) => (card === null || card === void 0 ? void 0 : card.onCardAddedToHand) !== undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card.interface.js","sourceRoot":"","sources":["../../src/cards/card.interface.ts"],"names":[],"mappings":"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","sourcesContent":["import { BgsPlayerEntity, BgsQuestEntity, BoardTrinket } from '../bgs-player-entity';\r\nimport { BoardEnchantment, BoardEntity } from '../board-entity';\r\nimport { BoardSecret } from '../board-secret';\r\nimport { OnDivineShieldUpdatedInput } from '../keywords/divine-shield';\r\nimport { OnRebornUpdatedInput } from '../keywords/reborn';\r\nimport { OnStealthUpdatedInput } from '../keywords/stealth';\r\nimport { OnTauntUpdatedInput } from '../keywords/taunt';\r\nimport { OnVenomousUpdatedInput } from '../keywords/venomous';\r\nimport { OnWindfuryUpdatedInput } from '../keywords/windfury';\r\nimport { OnGlobalInfoUpdatedInput } from '../mechanics/player-global-effects';\r\nimport {\r\n\tOnDespawnInput,\r\n\tOnFriendlyMinionSummonedTrinketInput,\r\n\tOnOtherSpawnAuraInput,\r\n\tOnOtherSpawnInput,\r\n\tOnSpawnInput,\r\n} from '../simulation/add-minion-to-board';\r\nimport {\r\n\tOnAfterDeathInput,\r\n\tOnAfterFriendlyMinionDeathInput,\r\n\tOnDeathInput,\r\n\tOnMinionKilledInput,\r\n} from '../simulation/attack';\r\nimport { AvengeInput } from '../simulation/avenge';\r\nimport { BattlecryInput, OnBattlecryTriggeredInput } from '../simulation/battlecries';\r\nimport { PlayedBloodGemsOnAnyInput, PlayedBloodGemsOnMeInput } from '../simulation/blood-gems';\r\nimport { OnCardAddedToHandInput } from '../simulation/cards-in-hand';\r\nimport { AfterDealDamageInput, AfterFriendlyMinionDamagedInput } from '../simulation/damage-effects';\r\nimport { AfterHeroDamagedInput } from '../simulation/damage-to-hero';\r\nimport { DeathrattleTriggeredInput } from '../simulation/deathrattle-on-trigger';\r\nimport { FullGameState } from '../simulation/internal-game-state';\r\nimport {\r\n\tOnAfterMagnetizeInput,\r\n\tOnAfterMagnetizeSelfInput,\r\n\tOnBeforeMagnetizeInput,\r\n\tOnBeforeMagnetizeSelfInput,\r\n} from '../simulation/magnetize';\r\nimport { OnAttackInput } from '../simulation/on-attack';\r\nimport { OnMinionAttackedInput } from '../simulation/on-being-attacked';\r\nimport { RebornEffectInput } from '../simulation/reborn';\r\nimport { SoCInput } from '../simulation/start-of-combat/start-of-combat-input';\r\nimport { OnStatsChangedInput } from '../simulation/stats';\r\nimport { OnGildedInput } from '../simulation/utils/golden';\r\n\r\nexport interface Card {\r\n\t// Maybe should make this mandatory\r\n\tcardIds?: readonly string[];\r\n\t// Method syntax keeps parameters bivariant so implementations can narrow (e.g. BoardEntity).\r\n\tstartOfCombat?(\r\n\t\ttrinket: BoardEntity | BoardTrinket | BgsPlayerEntity | BoardSecret,\r\n\t\tinput: SoCInput,\r\n\t): boolean | { hasTriggered: boolean; shouldRecomputeCurrentAttacker: boolean };\r\n}\r\n\r\nexport interface DefaultChargesCard extends Card {\r\n\tdefaultCharges(entity: BoardEntity): number;\r\n}\r\nexport const hasDefaultCharges = (card: Card): card is DefaultChargesCard =>\r\n\t(card as DefaultChargesCard)?.defaultCharges !== undefined;\r\n\r\nexport interface StartOfCombatCard extends Card {\r\n\tstartOfCombatTiming?: StartOfCombatTiming;\r\n\tstartOfCombat(\r\n\t\ttrinket: BoardEntity | BoardTrinket | BgsPlayerEntity | BoardSecret,\r\n\t\tinput: SoCInput,\r\n\t): boolean | { hasTriggered: boolean; shouldRecomputeCurrentAttacker: boolean };\r\n}\r\nexport const hasStartOfCombat = (card: Card): card is StartOfCombatCard =>\r\n\t(card as StartOfCombatCard)?.startOfCombat !== undefined;\r\nexport interface StartOfCombatFromHandCard extends StartOfCombatCard {\r\n\tstartOfCombatFromHand: true;\r\n}\r\nexport const hasStartOfCombatFromHand = (card: Card): card is StartOfCombatFromHandCard =>\r\n\t(card as StartOfCombatFromHandCard)?.startOfCombatFromHand !== undefined;\r\nexport type StartOfCombatTiming = 'start-of-combat' | 'pre-combat' | 'illidan';\r\n\r\nexport interface TavernSpellCard extends Card {\r\n\tcastTavernSpell(spellCardId: string, input: CastSpellInput): void;\r\n}\r\nexport const hasCastTavernSpell = (card: Card): card is TavernSpellCard =>\r\n\t(card as TavernSpellCard)?.castTavernSpell !== undefined;\r\n\r\nexport interface OnTavernSpellCastCard extends Card {\r\n\tonTavernSpellCast(entity: BoardEntity | BoardTrinket, input: CastSpellInput): void;\r\n}\r\nexport const hasOnTavernSpellCast = (card: Card): card is OnTavernSpellCastCard =>\r\n\t(card as OnTavernSpellCastCard)?.onTavernSpellCast !== undefined;\r\n\r\nexport interface OnBeforeTavernSpellCastCard extends Card {\r\n\tonBeforeTavernSpellCast(entity: BoardEntity | BoardTrinket, input: CastSpellInput): void;\r\n}\r\nexport const hasOnBeforeTavernSpellCast = (card: Card): card is OnBeforeTavernSpellCastCard =>\r\n\t(card as OnBeforeTavernSpellCastCard)?.onBeforeTavernSpellCast !== undefined;\r\n\r\nexport interface AfterTavernSpellCastCard extends Card {\r\n\tafterTavernSpellCast(entity: BoardEntity | BoardTrinket, input: CastSpellInput): void;\r\n}\r\nexport const hasAfterTavernSpellCast = (card: Card): card is AfterTavernSpellCastCard =>\r\n\t(card as AfterTavernSpellCastCard)?.afterTavernSpellCast !== undefined;\r\n\r\n// Whenever this attacks\r\nexport interface RallyCard extends Card {\r\n\trally(\r\n\t\tminion: BoardEntity | BoardTrinket | BoardEnchantment,\r\n\t\tinput: OnAttackInput,\r\n\t): { dmgDoneByAttacker: number; dmgDoneByDefender: number };\r\n}\r\nexport const hasRally = (card: Card): card is RallyCard => (card as RallyCard)?.rally !== undefined;\r\n\r\nexport interface OnWheneverAnotherMinionAttacksCard extends Card {\r\n\tonWheneverAnotherMinionAttacks(\r\n\t\tminion: BoardEntity | BoardTrinket | BoardEnchantment,\r\n\t\tinput: OnAttackInput,\r\n\t): { dmgDoneByAttacker: number; dmgDoneByDefender: number };\r\n}\r\nexport const hasOnWheneverAnotherMinionAttacks = (card: Card): card is OnWheneverAnotherMinionAttacksCard =>\r\n\t(card as OnWheneverAnotherMinionAttacksCard)?.onWheneverAnotherMinionAttacks !== undefined;\r\n\r\nexport interface AfterAnotherMinionAttacksCard extends Card {\r\n\tafterAnotherMinionAttacks(\r\n\t\tminion: BoardEntity | BoardTrinket | BoardEnchantment,\r\n\t\tinput: OnAttackInput,\r\n\t): { dmgDoneByAttacker: number; dmgDoneByDefender: number };\r\n}\r\nexport const hasAfterAnotherMinionAttacks = (card: Card): card is AfterAnotherMinionAttacksCard =>\r\n\t(card as AfterAnotherMinionAttacksCard)?.afterAnotherMinionAttacks !== undefined;\r\n\r\nexport interface OnMinionAttackedCard extends Card {\r\n\tonAttacked(minion: BoardEntity, input: OnMinionAttackedInput): void;\r\n}\r\nexport const hasOnMinionAttacked = (card: Card): card is OnMinionAttackedCard =>\r\n\t(card as OnMinionAttackedCard)?.onAttacked !== undefined;\r\n\r\nexport interface OnSpawnedCard extends Card {\r\n\tonSpawned(minion: BoardEntity, input: OnSpawnInput): void;\r\n}\r\nexport const hasOnSpawned = (card: Card): card is OnSpawnedCard => (card as OnSpawnedCard)?.onSpawned !== undefined;\r\nexport interface OnSpawnedEnchantmentCard extends Card {\r\n\tonSpawnedEnchantment(minion: BoardEntity, enchantment: BoardEnchantment, input: OnSpawnInput): void;\r\n}\r\nexport const hasOnSpawnedEnchantment = (card: Card): card is OnSpawnedEnchantmentCard =>\r\n\t(card as OnSpawnedEnchantmentCard)?.onSpawnedEnchantment !== undefined;\r\n\r\nexport interface OnOtherSpawnedAuraCard extends Card {\r\n\tonOtherSpawnedAura(minion: BoardEntity, input: OnOtherSpawnAuraInput): void;\r\n}\r\nexport const hasOnOtherAuraSpawned = (card: Card): card is OnOtherSpawnedAuraCard =>\r\n\t(card as OnOtherSpawnedAuraCard)?.onOtherSpawnedAura !== undefined;\r\n\r\nexport interface OnOtherSpawnedCard extends Card {\r\n\tonOtherSpawned(minion: BoardEntity | BoardTrinket, input: OnOtherSpawnInput): void;\r\n}\r\nexport const hasOnOtherSpawned = (card: Card): card is OnOtherSpawnedCard =>\r\n\t(card as OnOtherSpawnedCard)?.onOtherSpawned !== undefined;\r\n\r\nexport interface AfterOtherSpawnedCard extends Card {\r\n\tafterOtherSpawned(minion: BoardEntity | BoardTrinket, input: OnOtherSpawnInput): void;\r\n}\r\nexport const hasAfterOtherSpawned = (card: Card): card is AfterOtherSpawnedCard =>\r\n\t(card as AfterOtherSpawnedCard)?.afterOtherSpawned !== undefined;\r\n\r\nexport interface OnFriendlyMinionSummonedTrinketCard extends Card {\r\n\tonFriendlyMinionSummoned(trinket: BoardTrinket, input: OnFriendlyMinionSummonedTrinketInput): void;\r\n}\r\nexport const hasOnFriendlyMinionSummonedTrinket = (card: Card): card is OnFriendlyMinionSummonedTrinketCard =>\r\n\t(card as OnFriendlyMinionSummonedTrinketCard)?.onFriendlyMinionSummoned !== undefined;\r\n\r\nexport interface OnDespawnedCard extends Card {\r\n\tonDespawned(minion: BoardEntity, input: OnDespawnInput): void;\r\n}\r\nexport const hasOnDespawned = (card: Card): card is OnDespawnedCard =>\r\n\t(card as OnDespawnedCard)?.onDespawned !== undefined;\r\n\r\nexport const OnDespawnedEnchantmentCard = (card: Card): card is OnDespawnedEnchantmentCard =>\r\n\t(card as OnDespawnedEnchantmentCard)?.onDespawnedEnchantment !== undefined;\r\nexport interface OnDespawnedEnchantmentCard extends Card {\r\n\tonDespawnedEnchantment(minion: BoardEntity, enchantment: BoardEnchantment, input: OnDespawnInput): void;\r\n}\r\nexport const hasOnDespawnedEnchantment = (card: Card): card is OnDespawnedEnchantmentCard =>\r\n\t(card as OnDespawnedEnchantmentCard)?.onDespawnedEnchantment !== undefined;\r\n\r\nexport interface DeathrattleSpawnCard extends Card {\r\n\tdeathrattleSpawn(minion: BoardEntity, input: DeathrattleTriggeredInput): readonly BoardEntity[];\r\n}\r\nexport const hasDeathrattleSpawn = (card: Card): card is DeathrattleSpawnCard =>\r\n\t(card as DeathrattleSpawnCard)?.deathrattleSpawn !== undefined;\r\n\r\n/** Deathrattle that does not return board spawns (hand buffs, stat grants, etc.). */\r\nexport interface DeathrattleEffectCard extends Card {\r\n\tdeathrattleEffect(minion: BoardEntity, input: DeathrattleTriggeredInput): void;\r\n}\r\nexport const hasDeathrattleEffect = (card: Card): card is DeathrattleEffectCard =>\r\n\t(card as DeathrattleEffectCard)?.deathrattleEffect !== undefined;\r\n\r\nexport interface BattlecryCard extends Card {\r\n\t// boolean return type is used only for conditional battlecries (eg cards that only work as battlecries if a specific trinket\r\n\t// is in game)\r\n\tbattlecry(minion: BoardEntity, input: BattlecryInput): boolean;\r\n}\r\nexport const hasBattlecry = (card: Card): card is BattlecryCard => (card as BattlecryCard)?.battlecry !== undefined;\r\n\r\nexport interface RebornEffectCard extends Card {\r\n\trebornEffect(minion: BoardEntity | BoardTrinket, input: RebornEffectInput): void;\r\n}\r\nexport const hasRebornEffect = (card: Card): card is RebornEffectCard =>\r\n\t(card as RebornEffectCard)?.rebornEffect !== undefined;\r\n\r\nexport interface RebornSelfEffectCard extends Card {\r\n\trebornSelfEffect(minion: BoardEntity, input: RebornEffectInput): void;\r\n}\r\nexport const hasRebornSelfEffect = (card: Card): card is RebornSelfEffectCard =>\r\n\t(card as RebornSelfEffectCard)?.rebornSelfEffect !== undefined;\r\n\r\nexport interface BeforeRebornSelfEffectCard extends Card {\r\n\tbeforeRebornSelfEffect(minion: BoardEntity, input: RebornEffectInput): void;\r\n}\r\nexport const hasBeforeRebornSelfEffect = (card: Card): card is BeforeRebornSelfEffectCard =>\r\n\t(card as BeforeRebornSelfEffectCard)?.beforeRebornSelfEffect !== undefined;\r\n\r\n// When a minion is reborn, some attributes need to be transferred to the new minion\r\nexport interface RebornSelfAttributeTransferCard extends Card {\r\n\trebornSelfAttributeTransfer: (keyof BoardEntity)[];\r\n}\r\nexport const hasRebornSelfAttributeTransfer = (card: Card): card is RebornSelfAttributeTransferCard =>\r\n\t(card as RebornSelfAttributeTransferCard)?.rebornSelfAttributeTransfer !== undefined;\r\n\r\nexport interface AfterRebornCard extends Card {\r\n\tafterReborn(minion: BoardEntity | BoardTrinket, input: RebornEffectInput): void;\r\n}\r\nexport const hasAfterReborn = (card: Card): card is AfterRebornCard =>\r\n\t(card as AfterRebornCard)?.afterReborn !== undefined;\r\n\r\nexport interface OnBattlecryTriggeredCard extends Card {\r\n\tonBattlecryTriggered(minion: BoardEntity | BoardTrinket, input: OnBattlecryTriggeredInput): void;\r\n}\r\nexport const hasOnBattlecryTriggered = (card: Card): card is OnBattlecryTriggeredCard =>\r\n\t(card as OnBattlecryTriggeredCard)?.onBattlecryTriggered !== undefined;\r\n\r\nexport interface AvengeCard extends Card {\r\n\tavenge(minion: BoardEntity | BoardTrinket, input: AvengeInput): void | readonly BoardEntity[];\r\n\tbaseAvengeValue(cardId: string): number;\r\n}\r\nexport const hasAvenge = (card: Card): card is AvengeCard => (card as AvengeCard)?.avenge !== undefined;\r\n\r\nexport interface DefaultScriptDataNumCard extends Card {\r\n\tdefaultScriptDataNum(cardId: string): number;\r\n}\r\nexport const hasDefaultScriptDataNum = (card: Card): card is DefaultScriptDataNumCard =>\r\n\t(card as DefaultScriptDataNumCard)?.defaultScriptDataNum !== undefined;\r\n\r\n/** To use when another deathrattle is triggered */\r\nexport interface DeathrattleTriggeredCard extends Card {\r\n\tonDeathrattleTriggered(\r\n\t\tminion: BoardEntity | BoardTrinket | BoardEnchantment,\r\n\t\tinput: DeathrattleTriggeredInput,\r\n\t): void;\r\n}\r\nexport const hasOnDeathrattleTriggered = (card: Card): card is DeathrattleTriggeredCard =>\r\n\t(card as DeathrattleTriggeredCard)?.onDeathrattleTriggered !== undefined;\r\n\r\n// export interface DeathrattleEnchantmentEffectCard extends Card {\r\n// \tdeathrattleEffectEnchantmentEffect: (\r\n// \t\tminion: { cardId: string; originEntityId?: number; repeats?: number },\r\n// \t\tinput: DeathrattleTriggeredInput,\r\n// \t) => void;\r\n// \tcardIds: readonly string[];\r\n// }\r\n// export const hasDeathrattleEnchantmentEffect = (card: Card): card is DeathrattleEnchantmentEffectCard =>\r\n// \t(card as DeathrattleEnchantmentEffectCard)?.deathrattleEffectEnchantmentEffect !== undefined;\r\n\r\n/** Despite the name, this covers all deathrattle effects on an enchantment, not just the spawning ones */\r\nexport interface DeathrattleSpawnEnchantmentCard extends Card {\r\n\tdeathrattleSpawnEnchantmentEffect(\r\n\t\tenchantment: BoardEnchantment,\r\n\t\tminion: BoardEntity | null | undefined,\r\n\t\tinput: DeathrattleTriggeredInput,\r\n\t): readonly BoardEntity[];\r\n\tcardIds: readonly string[];\r\n}\r\nexport const hasDeathrattleSpawnEnchantment = (card: Card): card is DeathrattleSpawnEnchantmentCard =>\r\n\t(card as DeathrattleSpawnEnchantmentCard)?.deathrattleSpawnEnchantmentEffect !== undefined;\r\n\r\nexport interface OnCardAddedToHandCard extends Card {\r\n\tonCardAddedToHand(entity: BoardEntity | BgsQuestEntity | BoardTrinket, input: OnCardAddedToHandInput): void;\r\n}\r\nexport const hasOnCardAddedToHand = (card: Card): card is OnCardAddedToHandCard =>\r\n\t(card as OnCardAddedToHandCard)?.onCardAddedToHand !== undefined;\r\n\r\nexport interface EndOfTurnCard extends Card {\r\n\t// Use BattlecryInput because it's the only way end of turn effects are triggered\r\n\tendOfTurn(entity: BoardEntity, input: EndOfTurnInput): void;\r\n}\r\nexport const hasEndOfTurn = (card: Card): card is EndOfTurnCard => (card as EndOfTurnCard)?.endOfTurn !== undefined;\r\nexport type EndOfTurnInput = BattlecryInput;\r\n\r\nexport interface OnDivineShieldUpdatedCard extends Card {\r\n\tonDivineShieldUpdated(entity: BoardEntity | BoardTrinket, input: OnDivineShieldUpdatedInput): void;\r\n}\r\nexport const hasOnDivineShieldUpdated = (card: Card): card is OnDivineShieldUpdatedCard =>\r\n\t(card as OnDivineShieldUpdatedCard)?.onDivineShieldUpdated !== undefined;\r\n\r\nexport interface OnTauntUpdatedCard extends Card {\r\n\tonTauntUpdated(\r\n\t\tentity: BoardEntity,\r\n\t\timpactedEntity: BoardEntity,\r\n\t\tpreviousValue: boolean,\r\n\t\tinput: OnTauntUpdatedInput,\r\n\t): void;\r\n}\r\nexport const hasOnTauntUpdated = (card: Card): card is OnTauntUpdatedCard =>\r\n\t(card as OnTauntUpdatedCard)?.onTauntUpdated !== undefined;\r\n\r\nexport interface OnRebornUpdatedCard extends Card {\r\n\tonRebornUpdated(\r\n\t\tentity: BoardEntity,\r\n\t\timpactedEntity: BoardEntity,\r\n\t\tpreviousValue: boolean,\r\n\t\tinput: OnRebornUpdatedInput,\r\n\t): void;\r\n}\r\nexport const hasOnRebornUpdated = (card: Card): card is OnRebornUpdatedCard =>\r\n\t(card as OnRebornUpdatedCard)?.onRebornUpdated !== undefined;\r\n\r\nexport interface OnStealthUpdatedCard extends Card {\r\n\tonStealthUpdated(\r\n\t\tentity: BoardEntity,\r\n\t\timpactedEntity: BoardEntity,\r\n\t\tpreviousValue: boolean,\r\n\t\tinput: OnStealthUpdatedInput,\r\n\t): void;\r\n}\r\nexport const hasOnStealthUpdated = (card: Card): card is OnStealthUpdatedCard =>\r\n\t(card as OnStealthUpdatedCard)?.onStealthUpdated !== undefined;\r\n\r\nexport interface OnVenomousUpdatedCard extends Card {\r\n\tonVenomousUpdated(\r\n\t\tentity: BoardEntity,\r\n\t\timpactedEntity: BoardEntity,\r\n\t\tpreviousValue: boolean,\r\n\t\tinput: OnVenomousUpdatedInput,\r\n\t): void;\r\n}\r\nexport const hasOnVenomousUpdated = (card: Card): card is OnVenomousUpdatedCard =>\r\n\t(card as OnVenomousUpdatedCard)?.onVenomousUpdated !== undefined;\r\n\r\nexport interface OnWindfuryUpdatedCard extends Card {\r\n\tonWindfuryUpdated(\r\n\t\tentity: BoardEntity,\r\n\t\timpactedEntity: BoardEntity,\r\n\t\tpreviousValue: boolean,\r\n\t\tinput: OnWindfuryUpdatedInput,\r\n\t): void;\r\n}\r\nexport const hasOnWindfuryUpdated = (card: Card): card is OnWindfuryUpdatedCard =>\r\n\t(card as OnWindfuryUpdatedCard)?.onWindfuryUpdated !== undefined;\r\n\r\nexport interface OnStatsChangedCard extends Card {\r\n\tonStatsChanged(entity: BoardEntity, input: OnStatsChangedInput): void;\r\n}\r\nexport const hasOnStatsChanged = (card: Card): card is OnStatsChangedCard =>\r\n\t(card as OnStatsChangedCard)?.onStatsChanged !== undefined;\r\n\r\nexport interface AfterHeroDamagedCard extends Card {\r\n\tafterHeroDamaged(entity: BoardEntity | BoardTrinket, input: AfterHeroDamagedInput): void;\r\n}\r\nexport const hasAfterHeroDamaged = (card: Card): card is AfterHeroDamagedCard =>\r\n\t(card as AfterHeroDamagedCard)?.afterHeroDamaged !== undefined;\r\n\r\nexport interface OnDamagedCard extends Card {\r\n\tonDamaged(entity: BoardEntity, input: OnDamagedInput): void;\r\n}\r\nexport const hasOnDamaged = (card: Card): card is OnDamagedCard => (card as OnDamagedCard)?.onDamaged !== undefined;\r\n\r\nexport interface AfterDealDamageCard extends Card {\r\n\t// Called whenever damage is dealt, both on the friendly and enemy side\r\n\t// So you need to check the \"friendly\" flag\r\n\t// TODO: the \"after\" here waits for spawns, eg reborn / deathrattle\r\n\t// eg https://replays.firestoneapp.com/?reviewId=05860f41-1ea4-41f8-9c55-b6c854fa5f5a&turn=17&action=10\r\n\t// The reborn Rylak is buffed by Lord of the Ruins\r\n\tafterDealDamage(entity: BoardEntity, input: AfterDealDamageInput): void;\r\n}\r\nexport const hasAfterDealDamage = (card: Card): card is AfterDealDamageCard =>\r\n\t(card as AfterDealDamageCard)?.afterDealDamage !== undefined;\r\n\r\nexport interface AfterFriendlyMinionDamagedTrinketCard extends Card {\r\n\tafterFriendlyMinionDamaged(trinket: BoardTrinket, input: AfterFriendlyMinionDamagedInput): void;\r\n}\r\nexport const hasAfterFriendlyMinionDamagedTrinket = (card: Card): card is AfterFriendlyMinionDamagedTrinketCard =>\r\n\t(card as AfterFriendlyMinionDamagedTrinketCard)?.afterFriendlyMinionDamaged !== undefined;\r\n\r\nexport interface OnDeathCard extends Card {\r\n\tonDeath(entity: BoardEntity, input: OnDeathInput): void;\r\n}\r\nexport const hasOnDeath = (card: Card): card is OnDeathCard => (card as OnDeathCard)?.onDeath !== undefined;\r\n\r\nexport interface OnAfterDeathCard extends Card {\r\n\tonAfterDeath(entity: BoardEntity | BoardTrinket, input: OnAfterDeathInput): void;\r\n}\r\nexport const hasOnAfterDeath = (card: Card): card is OnAfterDeathCard =>\r\n\t(card as OnAfterDeathCard)?.onAfterDeath !== undefined;\r\n\r\n/**\r\n * After any friendly board minion dies (during `applyWheneverMinionDiesEffect`). Filter in the card\r\n * (e.g. only if `input.deadEntity.taunt`). Board minions and trinkets that implement this are dispatched\r\n * from `deathrattle-effects`.\r\n */\r\nexport interface OnAfterFriendlyMinionDeathCard extends Card {\r\n\tonAfterFriendlyMinionDeath(listener: BoardEntity | BoardTrinket, input: OnAfterFriendlyMinionDeathInput): void;\r\n}\r\nexport const hasOnAfterFriendlyMinionDeath = (card: Card): card is OnAfterFriendlyMinionDeathCard =>\r\n\t(card as OnAfterFriendlyMinionDeathCard)?.onAfterFriendlyMinionDeath !== undefined;\r\n\r\nexport interface OnMinionKilledCard extends Card {\r\n\tonMinionKilled(\r\n\t\tentity: BoardEntity,\r\n\t\tinput: OnMinionKilledInput,\r\n\t): { dmgDoneByAttacker: number; dmgDoneByDefender: number };\r\n}\r\nexport const hasOnMinionKilled = (card: Card): card is OnMinionKilledCard =>\r\n\t(card as OnMinionKilledCard)?.onMinionKilled !== undefined;\r\n\r\nexport interface OnBeforeMagnetizeCard extends Card {\r\n\tonBeforeMagnetize(entity: BoardEntity | BoardTrinket, input: OnBeforeMagnetizeInput): void;\r\n}\r\nexport const hasOnBeforeMagnetize = (card: Card): card is OnBeforeMagnetizeCard =>\r\n\t(card as OnBeforeMagnetizeCard)?.onBeforeMagnetize !== undefined;\r\n\r\nexport interface OnBeforeMagnetizeSelfCard extends Card {\r\n\tonBeforeMagnetizeSelf(entity: BoardEntity, input: OnBeforeMagnetizeSelfInput): void;\r\n}\r\nexport const hasOnBeforeMagnetizeSelf = (card: Card): card is OnBeforeMagnetizeSelfCard =>\r\n\t(card as OnBeforeMagnetizeSelfCard)?.onBeforeMagnetizeSelf !== undefined;\r\n\r\nexport interface OnAfterMagnetizeToSelfCard extends Card {\r\n\tonAfterMagnetizeToSelf(entity: BoardEntity, input: OnAfterMagnetizeSelfInput): void;\r\n}\r\nexport const hasOnAfterMagnetizeToSelf = (card: Card): card is OnAfterMagnetizeToSelfCard =>\r\n\t(card as OnAfterMagnetizeToSelfCard)?.onAfterMagnetizeToSelf !== undefined;\r\n\r\nexport interface OnAfterMagnetizeSelfCard extends Card {\r\n\tonAfterMagnetizeSelf(entity: BoardEntity, input: OnAfterMagnetizeInput): void;\r\n}\r\nexport const hasOnAfterMagnetizeSelf = (card: Card): card is OnAfterMagnetizeSelfCard =>\r\n\t(card as OnAfterMagnetizeSelfCard)?.onAfterMagnetizeSelf !== undefined;\r\n\r\nexport interface OnAfterMagnetizeCard extends Card {\r\n\tonAfterMagnetize(entity: BoardEntity | BoardTrinket, input: OnAfterMagnetizeInput): void;\r\n}\r\nexport const hasOnAfterMagnetize = (card: Card): card is OnAfterMagnetizeCard =>\r\n\t(card as OnAfterMagnetizeCard)?.onAfterMagnetize !== undefined;\r\n\r\nexport interface OnSpawnFailCard extends Card {\r\n\tonSpawnFail(entity: BoardEntity, input: OnSpawnFailInput): void;\r\n}\r\nexport const hasOnSpawnFail = (card: Card): card is OnSpawnFailCard =>\r\n\t(card as OnSpawnFailCard)?.onSpawnFail !== undefined;\r\n\r\nexport interface PlayedBloodGemsOnMeCard extends Card {\r\n\tplayedBloodGemsOnMe(entity: BoardEntity, input: PlayedBloodGemsOnMeInput): void;\r\n}\r\nexport const hasPlayedBloodGemsOnMe = (card: Card): card is PlayedBloodGemsOnMeCard =>\r\n\t(card as PlayedBloodGemsOnMeCard)?.playedBloodGemsOnMe !== undefined;\r\n\r\nexport interface PlayedBloodGemsOnAnyCard extends Card {\r\n\tplayedBloodGemsOnAny(entity: BoardEntity, input: PlayedBloodGemsOnAnyInput): void;\r\n}\r\nexport const hasPlayedBloodGemsOnAny = (card: Card): card is PlayedBloodGemsOnAnyCard =>\r\n\t(card as PlayedBloodGemsOnAnyCard)?.playedBloodGemsOnAny !== undefined;\r\n\r\nexport interface OnGlobalInfoUpdatedCard extends Card {\r\n\tonGlobalInfoUpdated(entity: BoardEntity, input: OnGlobalInfoUpdatedInput): void;\r\n}\r\nexport const hasOnGlobalInfoUpdated = (card: Card): card is OnGlobalInfoUpdatedCard =>\r\n\t(card as OnGlobalInfoUpdatedCard)?.onGlobalInfoUpdated !== undefined;\r\n\r\nexport interface OnGlobalInfoUpdatedEnchantmentCard extends Card {\r\n\tonGlobalInfoUpdatedEnchantment(\r\n\t\tentity: BoardEntity,\r\n\t\tenchantment: BoardEnchantment,\r\n\t\tinput: OnGlobalInfoUpdatedInput,\r\n\t): void;\r\n}\r\nexport const hasOnGlobalInfoUpdatedEnchantment = (card: Card): card is OnGlobalInfoUpdatedEnchantmentCard =>\r\n\t(card as OnGlobalInfoUpdatedEnchantmentCard)?.onGlobalInfoUpdatedEnchantment !== undefined;\r\n\r\nexport interface OnGildedCard extends Card {\r\n\tonGilded(entity: BoardEntity, input: OnGildedInput): void;\r\n}\r\nexport const hasOnGilded = (card: Card): card is OnGildedCard => (card as OnGildedCard)?.onGilded !== undefined;\r\n\r\nexport interface OnSpawnFailInput {\r\n\tfailedSpawn: BoardEntity;\r\n\tboard: BoardEntity[];\r\n\thero: BgsPlayerEntity;\r\n\tgameState: FullGameState;\r\n}\r\n\r\nexport interface CastSpellInput {\r\n\tspellCardId: string;\r\n\tsource: BoardEntity | BoardTrinket | BgsPlayerEntity;\r\n\ttarget: BoardEntity;\r\n\tboard: BoardEntity[];\r\n\thero: BgsPlayerEntity;\r\n\totherBoard: BoardEntity[];\r\n\totherHero: BgsPlayerEntity;\r\n\tgameState: FullGameState;\r\n}\r\nexport interface OnDamagedInput {\r\n\tdamagedEntity: BoardEntity;\r\n\tdamageDealer: BoardEntity | BgsPlayerEntity;\r\n\tdamage: number;\r\n\tboard: BoardEntity[];\r\n\thero: BgsPlayerEntity;\r\n\totherHero: BgsPlayerEntity;\r\n\tgameState: FullGameState;\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"card.interface.js","sourceRoot":"","sources":["../../src/cards/card.interface.ts"],"names":[],"mappings":"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","sourcesContent":["import { BgsPlayerEntity, BgsQuestEntity, BoardTrinket } from '../bgs-player-entity';\r\nimport { BoardEnchantment, BoardEntity } from '../board-entity';\r\nimport { BoardSecret } from '../board-secret';\r\nimport { OnDivineShieldUpdatedInput } from '../keywords/divine-shield';\r\nimport { OnRebornUpdatedInput } from '../keywords/reborn';\r\nimport { OnStealthUpdatedInput } from '../keywords/stealth';\r\nimport { OnTauntUpdatedInput } from '../keywords/taunt';\r\nimport { OnVenomousUpdatedInput } from '../keywords/venomous';\r\nimport { OnWindfuryUpdatedInput } from '../keywords/windfury';\r\nimport { OnGlobalInfoUpdatedInput } from '../mechanics/player-global-effects';\r\nimport {\r\n\tOnDespawnInput,\r\n\tOnFriendlyMinionSummonedTrinketInput,\r\n\tOnOtherSpawnAuraInput,\r\n\tOnOtherSpawnInput,\r\n\tOnSpawnInput,\r\n} from '../simulation/add-minion-to-board';\r\nimport {\r\n\tOnAfterDeathInput,\r\n\tOnAfterFriendlyMinionDeathInput,\r\n\tOnDeathInput,\r\n\tOnMinionKilledInput,\r\n} from '../simulation/attack';\r\nimport { AvengeInput } from '../simulation/avenge';\r\nimport { BattlecryInput, OnBattlecryTriggeredInput } from '../simulation/battlecries';\r\nimport { PlayedBloodGemsOnAnyInput, PlayedBloodGemsOnMeInput } from '../simulation/blood-gems';\r\nimport { OnCardAddedToHandInput } from '../simulation/cards-in-hand';\r\nimport { AfterDealDamageInput, AfterFriendlyMinionDamagedInput } from '../simulation/damage-effects';\r\nimport { AfterHeroDamagedInput } from '../simulation/damage-to-hero';\r\nimport { DeathrattleTriggeredInput } from '../simulation/deathrattle-on-trigger';\r\nimport { FullGameState } from '../simulation/internal-game-state';\r\nimport {\r\n\tOnAfterMagnetizeInput,\r\n\tOnAfterMagnetizeSelfInput,\r\n\tOnBeforeMagnetizeInput,\r\n\tOnBeforeMagnetizeSelfInput,\r\n} from '../simulation/magnetize';\r\nimport { OnAttackInput } from '../simulation/on-attack';\r\nimport { OnMinionAttackedInput } from '../simulation/on-being-attacked';\r\nimport { RebornEffectInput } from '../simulation/reborn';\r\nimport { SoCInput } from '../simulation/start-of-combat/start-of-combat-input';\r\nimport { OnStatsChangedInput } from '../simulation/stats';\r\nimport { OnGildedInput } from '../simulation/utils/golden';\r\n\r\nexport interface Card {\r\n\t// Maybe should make this mandatory\r\n\tcardIds?: readonly string[];\r\n\t// Method syntax keeps parameters bivariant so implementations can narrow (e.g. BoardEntity).\r\n\tstartOfCombat?(\r\n\t\ttrinket: BoardEntity | BoardTrinket | BgsPlayerEntity | BoardSecret,\r\n\t\tinput: SoCInput,\r\n\t): boolean | { hasTriggered: boolean; shouldRecomputeCurrentAttacker: boolean };\r\n}\r\n\r\nexport interface DefaultChargesCard extends Card {\r\n\tdefaultCharges(entity: BoardEntity): number;\r\n}\r\nexport const hasDefaultCharges = (card: Card): card is DefaultChargesCard =>\r\n\t(card as DefaultChargesCard)?.defaultCharges !== undefined;\r\n\r\nexport interface StartOfCombatCard extends Card {\r\n\tstartOfCombatTiming?: StartOfCombatTiming;\r\n\tstartOfCombat(\r\n\t\ttrinket: BoardEntity | BoardTrinket | BgsPlayerEntity | BoardSecret,\r\n\t\tinput: SoCInput,\r\n\t): boolean | { hasTriggered: boolean; shouldRecomputeCurrentAttacker: boolean };\r\n}\r\nexport const hasStartOfCombat = (card: Card): card is StartOfCombatCard =>\r\n\t(card as StartOfCombatCard)?.startOfCombat !== undefined;\r\nexport interface StartOfCombatFromHandCard extends StartOfCombatCard {\r\n\tstartOfCombatFromHand: true;\r\n}\r\nexport const hasStartOfCombatFromHand = (card: Card): card is StartOfCombatFromHandCard =>\r\n\t(card as StartOfCombatFromHandCard)?.startOfCombatFromHand !== undefined;\r\nexport type StartOfCombatTiming = 'start-of-combat' | 'pre-combat' | 'illidan';\r\n\r\nexport interface TavernSpellCard extends Card {\r\n\tcastTavernSpell(spellCardId: string, input: CastSpellInput): void;\r\n}\r\nexport const hasCastTavernSpell = (card: Card): card is TavernSpellCard =>\r\n\t(card as TavernSpellCard)?.castTavernSpell !== undefined;\r\n\r\nexport interface OnTavernSpellCastCard extends Card {\r\n\tonTavernSpellCast(entity: BoardEntity | BoardTrinket, input: CastSpellInput): void;\r\n}\r\nexport const hasOnTavernSpellCast = (card: Card): card is OnTavernSpellCastCard =>\r\n\t(card as OnTavernSpellCastCard)?.onTavernSpellCast !== undefined;\r\n\r\nexport interface OnBeforeTavernSpellCastCard extends Card {\r\n\tonBeforeTavernSpellCast(entity: BoardEntity | BoardTrinket, input: CastSpellInput): void;\r\n}\r\nexport const hasOnBeforeTavernSpellCast = (card: Card): card is OnBeforeTavernSpellCastCard =>\r\n\t(card as OnBeforeTavernSpellCastCard)?.onBeforeTavernSpellCast !== undefined;\r\n\r\nexport interface AfterTavernSpellCastCard extends Card {\r\n\tafterTavernSpellCast(entity: BoardEntity | BoardTrinket, input: CastSpellInput): void;\r\n}\r\nexport const hasAfterTavernSpellCast = (card: Card): card is AfterTavernSpellCastCard =>\r\n\t(card as AfterTavernSpellCastCard)?.afterTavernSpellCast !== undefined;\r\n\r\n// Whenever this attacks\r\nexport interface RallyCard extends Card {\r\n\trally(\r\n\t\tminion: BoardEntity | BoardTrinket | BoardEnchantment,\r\n\t\tinput: OnAttackInput,\r\n\t): { dmgDoneByAttacker: number; dmgDoneByDefender: number };\r\n}\r\nexport const hasRally = (card: Card): card is RallyCard => (card as RallyCard)?.rally !== undefined;\r\n\r\nexport interface OnWheneverAnotherMinionAttacksCard extends Card {\r\n\tonWheneverAnotherMinionAttacks(\r\n\t\tminion: BoardEntity | BoardTrinket | BoardEnchantment,\r\n\t\tinput: OnAttackInput,\r\n\t): { dmgDoneByAttacker: number; dmgDoneByDefender: number };\r\n}\r\nexport const hasOnWheneverAnotherMinionAttacks = (card: Card): card is OnWheneverAnotherMinionAttacksCard =>\r\n\t(card as OnWheneverAnotherMinionAttacksCard)?.onWheneverAnotherMinionAttacks !== undefined;\r\n\r\nexport interface AfterAnotherMinionAttacksCard extends Card {\r\n\tafterAnotherMinionAttacks(\r\n\t\tminion: BoardEntity | BoardTrinket | BoardEnchantment,\r\n\t\tinput: OnAttackInput,\r\n\t): { dmgDoneByAttacker: number; dmgDoneByDefender: number };\r\n}\r\nexport const hasAfterAnotherMinionAttacks = (card: Card): card is AfterAnotherMinionAttacksCard =>\r\n\t(card as AfterAnotherMinionAttacksCard)?.afterAnotherMinionAttacks !== undefined;\r\n\r\nexport interface OnMinionAttackedCard extends Card {\r\n\tonAttacked(minion: BoardEntity, input: OnMinionAttackedInput): void;\r\n}\r\nexport const hasOnMinionAttacked = (card: Card): card is OnMinionAttackedCard =>\r\n\t(card as OnMinionAttackedCard)?.onAttacked !== undefined;\r\n\r\nexport interface OnSpawnedCard extends Card {\r\n\tonSpawned(minion: BoardEntity, input: OnSpawnInput): void;\r\n}\r\nexport const hasOnSpawned = (card: Card): card is OnSpawnedCard => (card as OnSpawnedCard)?.onSpawned !== undefined;\r\nexport interface OnSpawnedEnchantmentCard extends Card {\r\n\tonSpawnedEnchantment(minion: BoardEntity, enchantment: BoardEnchantment, input: OnSpawnInput): void;\r\n}\r\nexport const hasOnSpawnedEnchantment = (card: Card): card is OnSpawnedEnchantmentCard =>\r\n\t(card as OnSpawnedEnchantmentCard)?.onSpawnedEnchantment !== undefined;\r\n\r\nexport interface OnOtherSpawnedAuraCard extends Card {\r\n\tonOtherSpawnedAura(minion: BoardEntity, input: OnOtherSpawnAuraInput): void;\r\n}\r\nexport const hasOnOtherAuraSpawned = (card: Card): card is OnOtherSpawnedAuraCard =>\r\n\t(card as OnOtherSpawnedAuraCard)?.onOtherSpawnedAura !== undefined;\r\n\r\nexport interface OnOtherSpawnedCard extends Card {\r\n\tonOtherSpawned(minion: BoardEntity | BoardTrinket, input: OnOtherSpawnInput): void;\r\n}\r\nexport const hasOnOtherSpawned = (card: Card): card is OnOtherSpawnedCard =>\r\n\t(card as OnOtherSpawnedCard)?.onOtherSpawned !== undefined;\r\n\r\nexport interface AfterOtherSpawnedCard extends Card {\r\n\tafterOtherSpawned(minion: BoardEntity | BoardTrinket, input: OnOtherSpawnInput): void;\r\n}\r\nexport const hasAfterOtherSpawned = (card: Card): card is AfterOtherSpawnedCard =>\r\n\t(card as AfterOtherSpawnedCard)?.afterOtherSpawned !== undefined;\r\n\r\nexport interface OnFriendlyMinionSummonedTrinketCard extends Card {\r\n\tonFriendlyMinionSummoned(trinket: BoardTrinket, input: OnFriendlyMinionSummonedTrinketInput): void;\r\n}\r\nexport const hasOnFriendlyMinionSummonedTrinket = (card: Card): card is OnFriendlyMinionSummonedTrinketCard =>\r\n\t(card as OnFriendlyMinionSummonedTrinketCard)?.onFriendlyMinionSummoned !== undefined;\r\n\r\nexport interface OnDespawnedCard extends Card {\r\n\tonDespawned(minion: BoardEntity, input: OnDespawnInput): void;\r\n}\r\nexport const hasOnDespawned = (card: Card): card is OnDespawnedCard =>\r\n\t(card as OnDespawnedCard)?.onDespawned !== undefined;\r\n\r\nexport const OnDespawnedEnchantmentCard = (card: Card): card is OnDespawnedEnchantmentCard =>\r\n\t(card as OnDespawnedEnchantmentCard)?.onDespawnedEnchantment !== undefined;\r\nexport interface OnDespawnedEnchantmentCard extends Card {\r\n\tonDespawnedEnchantment(minion: BoardEntity, enchantment: BoardEnchantment, input: OnDespawnInput): void;\r\n}\r\nexport const hasOnDespawnedEnchantment = (card: Card): card is OnDespawnedEnchantmentCard =>\r\n\t(card as OnDespawnedEnchantmentCard)?.onDespawnedEnchantment !== undefined;\r\n\r\nexport interface DeathrattleSpawnCard extends Card {\r\n\tdeathrattleSpawn(minion: BoardEntity, input: DeathrattleTriggeredInput): readonly BoardEntity[];\r\n}\r\nexport const hasDeathrattleSpawn = (card: Card): card is DeathrattleSpawnCard =>\r\n\t(card as DeathrattleSpawnCard)?.deathrattleSpawn !== undefined;\r\n\r\n/** Deathrattle that does not return board spawns (hand buffs, stat grants, etc.). */\r\nexport interface DeathrattleEffectCard extends Card {\r\n\tdeathrattleEffect(minion: BoardEntity, input: DeathrattleTriggeredInput): void;\r\n}\r\nexport const hasDeathrattleEffect = (card: Card): card is DeathrattleEffectCard =>\r\n\t(card as DeathrattleEffectCard)?.deathrattleEffect !== undefined;\r\n\r\nexport interface BattlecryCard extends Card {\r\n\t// boolean return type is used only for conditional battlecries (eg cards that only work as battlecries if a specific trinket\r\n\t// is in game)\r\n\tbattlecry(minion: BoardEntity, input: BattlecryInput): boolean;\r\n}\r\nexport const hasBattlecry = (card: Card): card is BattlecryCard => (card as BattlecryCard)?.battlecry !== undefined;\r\n\r\nexport interface RebornEffectCard extends Card {\r\n\trebornEffect(minion: BoardEntity | BoardTrinket, input: RebornEffectInput): void;\r\n}\r\nexport const hasRebornEffect = (card: Card): card is RebornEffectCard =>\r\n\t(card as RebornEffectCard)?.rebornEffect !== undefined;\r\n\r\nexport interface RebornSelfEffectCard extends Card {\r\n\trebornSelfEffect(minion: BoardEntity, input: RebornEffectInput): void;\r\n}\r\nexport const hasRebornSelfEffect = (card: Card): card is RebornSelfEffectCard =>\r\n\t(card as RebornSelfEffectCard)?.rebornSelfEffect !== undefined;\r\n\r\nexport interface BeforeRebornSelfEffectCard extends Card {\r\n\tbeforeRebornSelfEffect(minion: BoardEntity, input: RebornEffectInput): void;\r\n}\r\nexport const hasBeforeRebornSelfEffect = (card: Card): card is BeforeRebornSelfEffectCard =>\r\n\t(card as BeforeRebornSelfEffectCard)?.beforeRebornSelfEffect !== undefined;\r\n\r\n// When a minion is reborn, some attributes need to be transferred to the new minion\r\nexport interface RebornSelfAttributeTransferCard extends Card {\r\n\trebornSelfAttributeTransfer: (keyof BoardEntity)[];\r\n}\r\nexport const hasRebornSelfAttributeTransfer = (card: Card): card is RebornSelfAttributeTransferCard =>\r\n\t(card as RebornSelfAttributeTransferCard)?.rebornSelfAttributeTransfer !== undefined;\r\n\r\nexport interface AfterRebornCard extends Card {\r\n\tafterReborn(minion: BoardEntity | BoardTrinket, input: RebornEffectInput): void;\r\n}\r\nexport const hasAfterReborn = (card: Card): card is AfterRebornCard =>\r\n\t(card as AfterRebornCard)?.afterReborn !== undefined;\r\n\r\nexport interface OnBattlecryTriggeredCard extends Card {\r\n\tonBattlecryTriggered(minion: BoardEntity | BoardTrinket, input: OnBattlecryTriggeredInput): void;\r\n}\r\nexport const hasOnBattlecryTriggered = (card: Card): card is OnBattlecryTriggeredCard =>\r\n\t(card as OnBattlecryTriggeredCard)?.onBattlecryTriggered !== undefined;\r\n\r\nexport interface AvengeCard extends Card {\r\n\tavenge(minion: BoardEntity | BoardTrinket, input: AvengeInput): void | readonly BoardEntity[];\r\n\tbaseAvengeValue(cardId: string): number;\r\n}\r\nexport const hasAvenge = (card: Card): card is AvengeCard => (card as AvengeCard)?.avenge !== undefined;\r\n\r\nexport interface DefaultScriptDataNumCard extends Card {\r\n\tdefaultScriptDataNum(cardId: string): number;\r\n}\r\nexport const hasDefaultScriptDataNum = (card: Card): card is DefaultScriptDataNumCard =>\r\n\t(card as DefaultScriptDataNumCard)?.defaultScriptDataNum !== undefined;\r\n\r\n/** To use when another deathrattle is triggered */\r\nexport interface DeathrattleTriggeredCard extends Card {\r\n\tonDeathrattleTriggered(\r\n\t\tminion: BoardEntity | BoardTrinket | BoardEnchantment,\r\n\t\tinput: DeathrattleTriggeredInput,\r\n\t): void;\r\n}\r\nexport const hasOnDeathrattleTriggered = (card: Card): card is DeathrattleTriggeredCard =>\r\n\t(card as DeathrattleTriggeredCard)?.onDeathrattleTriggered !== undefined;\r\n\r\nexport interface DeathrattleTriggeredEnchantmentCard extends Card {\r\n\tonDeathrattleTriggeredEnchantment(\r\n\t\tenchantedMinion: BoardEntity,\r\n\t\tenchantment: BoardEnchantment,\r\n\t\tinput: DeathrattleTriggeredInput,\r\n\t): void;\r\n}\r\nexport const hasOnDeathrattleTriggeredEnchantment = (card: Card): card is DeathrattleTriggeredEnchantmentCard =>\r\n\t(card as DeathrattleTriggeredEnchantmentCard)?.onDeathrattleTriggeredEnchantment !== undefined;\r\n\r\n/** Despite the name, this covers all deathrattle effects on an enchantment, not just the spawning ones */\r\nexport interface DeathrattleSpawnEnchantmentCard extends Card {\r\n\tdeathrattleSpawnEnchantmentEffect(\r\n\t\tenchantment: BoardEnchantment,\r\n\t\tminion: BoardEntity | null | undefined,\r\n\t\tinput: DeathrattleTriggeredInput,\r\n\t): readonly BoardEntity[];\r\n\tcardIds: readonly string[];\r\n}\r\nexport const hasDeathrattleSpawnEnchantment = (card: Card): card is DeathrattleSpawnEnchantmentCard =>\r\n\t(card as DeathrattleSpawnEnchantmentCard)?.deathrattleSpawnEnchantmentEffect !== undefined;\r\n\r\nexport interface OnCardAddedToHandCard extends Card {\r\n\tonCardAddedToHand(entity: BoardEntity | BgsQuestEntity | BoardTrinket, input: OnCardAddedToHandInput): void;\r\n}\r\nexport const hasOnCardAddedToHand = (card: Card): card is OnCardAddedToHandCard =>\r\n\t(card as OnCardAddedToHandCard)?.onCardAddedToHand !== undefined;\r\n\r\nexport interface EndOfTurnCard extends Card {\r\n\t// Use BattlecryInput because it's the only way end of turn effects are triggered\r\n\tendOfTurn(entity: BoardEntity, input: EndOfTurnInput): void;\r\n}\r\nexport const hasEndOfTurn = (card: Card): card is EndOfTurnCard => (card as EndOfTurnCard)?.endOfTurn !== undefined;\r\nexport type EndOfTurnInput = BattlecryInput;\r\n\r\nexport interface OnDivineShieldUpdatedCard extends Card {\r\n\tonDivineShieldUpdated(entity: BoardEntity | BoardTrinket, input: OnDivineShieldUpdatedInput): void;\r\n}\r\nexport const hasOnDivineShieldUpdated = (card: Card): card is OnDivineShieldUpdatedCard =>\r\n\t(card as OnDivineShieldUpdatedCard)?.onDivineShieldUpdated !== undefined;\r\n\r\nexport interface OnTauntUpdatedCard extends Card {\r\n\tonTauntUpdated(\r\n\t\tentity: BoardEntity,\r\n\t\timpactedEntity: BoardEntity,\r\n\t\tpreviousValue: boolean,\r\n\t\tinput: OnTauntUpdatedInput,\r\n\t): void;\r\n}\r\nexport const hasOnTauntUpdated = (card: Card): card is OnTauntUpdatedCard =>\r\n\t(card as OnTauntUpdatedCard)?.onTauntUpdated !== undefined;\r\n\r\nexport interface OnRebornUpdatedCard extends Card {\r\n\tonRebornUpdated(\r\n\t\tentity: BoardEntity,\r\n\t\timpactedEntity: BoardEntity,\r\n\t\tpreviousValue: boolean,\r\n\t\tinput: OnRebornUpdatedInput,\r\n\t): void;\r\n}\r\nexport const hasOnRebornUpdated = (card: Card): card is OnRebornUpdatedCard =>\r\n\t(card as OnRebornUpdatedCard)?.onRebornUpdated !== undefined;\r\n\r\nexport interface OnStealthUpdatedCard extends Card {\r\n\tonStealthUpdated(\r\n\t\tentity: BoardEntity,\r\n\t\timpactedEntity: BoardEntity,\r\n\t\tpreviousValue: boolean,\r\n\t\tinput: OnStealthUpdatedInput,\r\n\t): void;\r\n}\r\nexport const hasOnStealthUpdated = (card: Card): card is OnStealthUpdatedCard =>\r\n\t(card as OnStealthUpdatedCard)?.onStealthUpdated !== undefined;\r\n\r\nexport interface OnVenomousUpdatedCard extends Card {\r\n\tonVenomousUpdated(\r\n\t\tentity: BoardEntity,\r\n\t\timpactedEntity: BoardEntity,\r\n\t\tpreviousValue: boolean,\r\n\t\tinput: OnVenomousUpdatedInput,\r\n\t): void;\r\n}\r\nexport const hasOnVenomousUpdated = (card: Card): card is OnVenomousUpdatedCard =>\r\n\t(card as OnVenomousUpdatedCard)?.onVenomousUpdated !== undefined;\r\n\r\nexport interface OnWindfuryUpdatedCard extends Card {\r\n\tonWindfuryUpdated(\r\n\t\tentity: BoardEntity,\r\n\t\timpactedEntity: BoardEntity,\r\n\t\tpreviousValue: boolean,\r\n\t\tinput: OnWindfuryUpdatedInput,\r\n\t): void;\r\n}\r\nexport const hasOnWindfuryUpdated = (card: Card): card is OnWindfuryUpdatedCard =>\r\n\t(card as OnWindfuryUpdatedCard)?.onWindfuryUpdated !== undefined;\r\n\r\nexport interface OnStatsChangedCard extends Card {\r\n\tonStatsChanged(entity: BoardEntity, input: OnStatsChangedInput): void;\r\n}\r\nexport const hasOnStatsChanged = (card: Card): card is OnStatsChangedCard =>\r\n\t(card as OnStatsChangedCard)?.onStatsChanged !== undefined;\r\n\r\nexport interface AfterHeroDamagedCard extends Card {\r\n\tafterHeroDamaged(entity: BoardEntity | BoardTrinket, input: AfterHeroDamagedInput): void;\r\n}\r\nexport const hasAfterHeroDamaged = (card: Card): card is AfterHeroDamagedCard =>\r\n\t(card as AfterHeroDamagedCard)?.afterHeroDamaged !== undefined;\r\n\r\nexport interface OnDamagedCard extends Card {\r\n\tonDamaged(entity: BoardEntity, input: OnDamagedInput): void;\r\n}\r\nexport const hasOnDamaged = (card: Card): card is OnDamagedCard => (card as OnDamagedCard)?.onDamaged !== undefined;\r\n\r\nexport interface AfterDealDamageCard extends Card {\r\n\t// Called whenever damage is dealt, both on the friendly and enemy side\r\n\t// So you need to check the \"friendly\" flag\r\n\t// TODO: the \"after\" here waits for spawns, eg reborn / deathrattle\r\n\t// eg https://replays.firestoneapp.com/?reviewId=05860f41-1ea4-41f8-9c55-b6c854fa5f5a&turn=17&action=10\r\n\t// The reborn Rylak is buffed by Lord of the Ruins\r\n\tafterDealDamage(entity: BoardEntity, input: AfterDealDamageInput): void;\r\n}\r\nexport const hasAfterDealDamage = (card: Card): card is AfterDealDamageCard =>\r\n\t(card as AfterDealDamageCard)?.afterDealDamage !== undefined;\r\n\r\nexport interface AfterFriendlyMinionDamagedTrinketCard extends Card {\r\n\tafterFriendlyMinionDamaged(trinket: BoardTrinket, input: AfterFriendlyMinionDamagedInput): void;\r\n}\r\nexport const hasAfterFriendlyMinionDamagedTrinket = (card: Card): card is AfterFriendlyMinionDamagedTrinketCard =>\r\n\t(card as AfterFriendlyMinionDamagedTrinketCard)?.afterFriendlyMinionDamaged !== undefined;\r\n\r\nexport interface OnDeathCard extends Card {\r\n\tonDeath(entity: BoardEntity, input: OnDeathInput): void;\r\n}\r\nexport const hasOnDeath = (card: Card): card is OnDeathCard => (card as OnDeathCard)?.onDeath !== undefined;\r\n\r\nexport interface OnAfterDeathCard extends Card {\r\n\tonAfterDeath(entity: BoardEntity | BoardTrinket, input: OnAfterDeathInput): void;\r\n}\r\nexport const hasOnAfterDeath = (card: Card): card is OnAfterDeathCard =>\r\n\t(card as OnAfterDeathCard)?.onAfterDeath !== undefined;\r\n\r\n/**\r\n * After any friendly board minion dies (during `applyWheneverMinionDiesEffect`). Filter in the card\r\n * (e.g. only if `input.deadEntity.taunt`). Board minions and trinkets that implement this are dispatched\r\n * from `deathrattle-effects`.\r\n */\r\nexport interface OnAfterFriendlyMinionDeathCard extends Card {\r\n\tonAfterFriendlyMinionDeath(listener: BoardEntity | BoardTrinket, input: OnAfterFriendlyMinionDeathInput): void;\r\n}\r\nexport const hasOnAfterFriendlyMinionDeath = (card: Card): card is OnAfterFriendlyMinionDeathCard =>\r\n\t(card as OnAfterFriendlyMinionDeathCard)?.onAfterFriendlyMinionDeath !== undefined;\r\n\r\nexport interface OnMinionKilledCard extends Card {\r\n\tonMinionKilled(\r\n\t\tentity: BoardEntity,\r\n\t\tinput: OnMinionKilledInput,\r\n\t): { dmgDoneByAttacker: number; dmgDoneByDefender: number };\r\n}\r\nexport const hasOnMinionKilled = (card: Card): card is OnMinionKilledCard =>\r\n\t(card as OnMinionKilledCard)?.onMinionKilled !== undefined;\r\n\r\nexport interface OnBeforeMagnetizeCard extends Card {\r\n\tonBeforeMagnetize(entity: BoardEntity | BoardTrinket, input: OnBeforeMagnetizeInput): void;\r\n}\r\nexport const hasOnBeforeMagnetize = (card: Card): card is OnBeforeMagnetizeCard =>\r\n\t(card as OnBeforeMagnetizeCard)?.onBeforeMagnetize !== undefined;\r\n\r\nexport interface OnBeforeMagnetizeSelfCard extends Card {\r\n\tonBeforeMagnetizeSelf(entity: BoardEntity, input: OnBeforeMagnetizeSelfInput): void;\r\n}\r\nexport const hasOnBeforeMagnetizeSelf = (card: Card): card is OnBeforeMagnetizeSelfCard =>\r\n\t(card as OnBeforeMagnetizeSelfCard)?.onBeforeMagnetizeSelf !== undefined;\r\n\r\nexport interface OnAfterMagnetizeToSelfCard extends Card {\r\n\tonAfterMagnetizeToSelf(entity: BoardEntity, input: OnAfterMagnetizeSelfInput): void;\r\n}\r\nexport const hasOnAfterMagnetizeToSelf = (card: Card): card is OnAfterMagnetizeToSelfCard =>\r\n\t(card as OnAfterMagnetizeToSelfCard)?.onAfterMagnetizeToSelf !== undefined;\r\n\r\nexport interface OnAfterMagnetizeSelfCard extends Card {\r\n\tonAfterMagnetizeSelf(entity: BoardEntity, input: OnAfterMagnetizeInput): void;\r\n}\r\nexport const hasOnAfterMagnetizeSelf = (card: Card): card is OnAfterMagnetizeSelfCard =>\r\n\t(card as OnAfterMagnetizeSelfCard)?.onAfterMagnetizeSelf !== undefined;\r\n\r\nexport interface OnAfterMagnetizeCard extends Card {\r\n\tonAfterMagnetize(entity: BoardEntity | BoardTrinket, input: OnAfterMagnetizeInput): void;\r\n}\r\nexport const hasOnAfterMagnetize = (card: Card): card is OnAfterMagnetizeCard =>\r\n\t(card as OnAfterMagnetizeCard)?.onAfterMagnetize !== undefined;\r\n\r\nexport interface OnSpawnFailCard extends Card {\r\n\tonSpawnFail(entity: BoardEntity, input: OnSpawnFailInput): void;\r\n}\r\nexport const hasOnSpawnFail = (card: Card): card is OnSpawnFailCard =>\r\n\t(card as OnSpawnFailCard)?.onSpawnFail !== undefined;\r\n\r\nexport interface PlayedBloodGemsOnMeCard extends Card {\r\n\tplayedBloodGemsOnMe(entity: BoardEntity, input: PlayedBloodGemsOnMeInput): void;\r\n}\r\nexport const hasPlayedBloodGemsOnMe = (card: Card): card is PlayedBloodGemsOnMeCard =>\r\n\t(card as PlayedBloodGemsOnMeCard)?.playedBloodGemsOnMe !== undefined;\r\n\r\nexport interface PlayedBloodGemsOnAnyCard extends Card {\r\n\tplayedBloodGemsOnAny(entity: BoardEntity, input: PlayedBloodGemsOnAnyInput): void;\r\n}\r\nexport const hasPlayedBloodGemsOnAny = (card: Card): card is PlayedBloodGemsOnAnyCard =>\r\n\t(card as PlayedBloodGemsOnAnyCard)?.playedBloodGemsOnAny !== undefined;\r\n\r\nexport interface OnGlobalInfoUpdatedCard extends Card {\r\n\tonGlobalInfoUpdated(entity: BoardEntity, input: OnGlobalInfoUpdatedInput): void;\r\n}\r\nexport const hasOnGlobalInfoUpdated = (card: Card): card is OnGlobalInfoUpdatedCard =>\r\n\t(card as OnGlobalInfoUpdatedCard)?.onGlobalInfoUpdated !== undefined;\r\n\r\nexport interface OnGlobalInfoUpdatedEnchantmentCard extends Card {\r\n\tonGlobalInfoUpdatedEnchantment(\r\n\t\tentity: BoardEntity,\r\n\t\tenchantment: BoardEnchantment,\r\n\t\tinput: OnGlobalInfoUpdatedInput,\r\n\t): void;\r\n}\r\nexport const hasOnGlobalInfoUpdatedEnchantment = (card: Card): card is OnGlobalInfoUpdatedEnchantmentCard =>\r\n\t(card as OnGlobalInfoUpdatedEnchantmentCard)?.onGlobalInfoUpdatedEnchantment !== undefined;\r\n\r\nexport interface OnGildedCard extends Card {\r\n\tonGilded(entity: BoardEntity, input: OnGildedInput): void;\r\n}\r\nexport const hasOnGilded = (card: Card): card is OnGildedCard => (card as OnGildedCard)?.onGilded !== undefined;\r\n\r\nexport interface OnSpawnFailInput {\r\n\tfailedSpawn: BoardEntity;\r\n\tboard: BoardEntity[];\r\n\thero: BgsPlayerEntity;\r\n\tgameState: FullGameState;\r\n}\r\n\r\nexport interface CastSpellInput {\r\n\tspellCardId: string;\r\n\tsource: BoardEntity | BoardTrinket | BgsPlayerEntity;\r\n\ttarget: BoardEntity;\r\n\tboard: BoardEntity[];\r\n\thero: BgsPlayerEntity;\r\n\totherBoard: BoardEntity[];\r\n\totherHero: BgsPlayerEntity;\r\n\tgameState: FullGameState;\r\n}\r\nexport interface OnDamagedInput {\r\n\tdamagedEntity: BoardEntity;\r\n\tdamageDealer: BoardEntity | BgsPlayerEntity;\r\n\tdamage: number;\r\n\tboard: BoardEntity[];\r\n\thero: BgsPlayerEntity;\r\n\totherHero: BgsPlayerEntity;\r\n\tgameState: FullGameState;\r\n}\r\n"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare const DeathsEmbrace:
|
|
1
|
+
import { DeathrattleTriggeredEnchantmentCard, OnDespawnedEnchantmentCard, OnSpawnedEnchantmentCard } from '../../card.interface';
|
|
2
|
+
export declare const DeathsEmbrace: DeathrattleTriggeredEnchantmentCard & OnSpawnedEnchantmentCard & OnDespawnedEnchantmentCard;
|
|
@@ -8,14 +8,14 @@ exports.DeathsEmbrace = {
|
|
|
8
8
|
"BG36_MidGameEffect_000t29te",
|
|
9
9
|
"BG36_MidGameEffect_000t29e",
|
|
10
10
|
],
|
|
11
|
-
|
|
11
|
+
onDeathrattleTriggeredEnchantment: (enchantedMinion, enchantment, input) => {
|
|
12
12
|
const mult = input.deadEntity.cardId === "BG36_MidGameEffect_000t29e"
|
|
13
13
|
? 2
|
|
14
14
|
: 1;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
enchantedMinion.attack += mult * atkBuff;
|
|
16
|
+
enchantedMinion.maxAttack += mult * atkBuff;
|
|
17
|
+
enchantedMinion.health += mult * healthBuff;
|
|
18
|
+
enchantedMinion.maxHealth += mult * healthBuff;
|
|
19
19
|
enchantment.tagScriptDataNum2 += 1;
|
|
20
20
|
return [];
|
|
21
21
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deaths-embrace.js","sourceRoot":"","sources":["../../../../src/cards/impl/enchantments/deaths-embrace.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"deaths-embrace.js","sourceRoot":"","sources":["../../../../src/cards/impl/enchantments/deaths-embrace.ts"],"names":[],"mappings":";;;AAcA,MAAM,OAAO,GAAG,CAAC,CAAC;AAClB,MAAM,UAAU,GAAG,CAAC,CAAC;AAKR,QAAA,aAAa,GAEI;IAC7B,OAAO,EAAE;;;KAGR;IACD,iCAAiC,EAAE,CAClC,eAA4B,EAC5B,WAA6B,EAC7B,KAAgC,EAChB,EAAE;QAClB,MAAM,IAAI,GACT,KAAK,CAAC,UAAU,CAAC,MAAM,iCAA8E;YACpG,CAAC,CAAC,CAAC;YACH,CAAC,CAAC,CAAC,CAAC;QACN,eAAe,CAAC,MAAM,IAAI,IAAI,GAAG,OAAO,CAAC;QACzC,eAAe,CAAC,SAAS,IAAI,IAAI,GAAG,OAAO,CAAC;QAC5C,eAAe,CAAC,MAAM,IAAI,IAAI,GAAG,UAAU,CAAC;QAC5C,eAAe,CAAC,SAAS,IAAI,IAAI,GAAG,UAAU,CAAC;QAC/C,WAAW,CAAC,iBAAiB,IAAI,CAAC,CAAC;QACnC,OAAO,EAAE,CAAC;IACX,CAAC;IAGD,oBAAoB,EAAE,CAAC,MAAmB,EAAE,WAA6B,EAAE,KAAmB,EAAE,EAAE;QACjG,MAAM,IAAI,GACT,WAAW,CAAC,MAAM,iCAA8E,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1G,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,6BAA6B,CAAC;QACjE,IAAI,KAAK,CAAC,gBAAgB,EAAE;YAC3B,MAAM,CAAC,MAAM,IAAI,IAAI,GAAG,OAAO,GAAG,IAAI,CAAC;YACvC,MAAM,CAAC,SAAS,IAAI,IAAI,GAAG,OAAO,GAAG,IAAI,CAAC;SAC1C;QACD,IAAI,KAAK,CAAC,gBAAgB,EAAE;YAC3B,MAAM,CAAC,MAAM,IAAI,IAAI,GAAG,UAAU,GAAG,IAAI,CAAC;YAC1C,MAAM,CAAC,SAAS,IAAI,IAAI,GAAG,UAAU,GAAG,IAAI,CAAC;SAC7C;QACD,WAAW,CAAC,iBAAiB,GAAG,IAAI,CAAC;IACtC,CAAC;IACD,sBAAsB,EAAE,CAAC,MAAmB,EAAE,WAA6B,EAAE,KAAqB,EAAE,EAAE;;QACrG,MAAM,IAAI,GACT,WAAW,CAAC,MAAM,iCAA8E,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1G,MAAM,IAAI,GAAG,MAAA,WAAW,CAAC,iBAAiB,mCAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,6BAA6B,CAAC;QAClG,IAAI,KAAK,CAAC,gBAAgB,EAAE;YAC3B,MAAM,CAAC,MAAM,IAAI,IAAI,GAAG,OAAO,GAAG,IAAI,CAAC;YACvC,MAAM,CAAC,SAAS,IAAI,IAAI,GAAG,OAAO,GAAG,IAAI,CAAC;SAC1C;QACD,IAAI,KAAK,CAAC,gBAAgB,EAAE;YAC3B,MAAM,CAAC,MAAM,IAAI,IAAI,GAAG,UAAU,GAAG,IAAI,CAAC;YAC1C,MAAM,CAAC,SAAS,IAAI,IAAI,GAAG,UAAU,GAAG,IAAI,CAAC;SAC7C;IACF,CAAC;CACD,CAAC","sourcesContent":["/**\r\n * Defensive Sacrifice (Dark Gift)\r\n * Deathrattle: Give this minion's max Health to another friendly minion.\r\n */\r\nimport { BoardEnchantment, BoardEntity } from '../../../board-entity';\r\nimport { CardIds } from '../../../services/card-ids';\r\nimport { OnDespawnInput, OnSpawnInput } from '../../../simulation/add-minion-to-board';\r\nimport { DeathrattleTriggeredInput } from '../../../simulation/deathrattle-on-trigger';\r\nimport {\r\n\tDeathrattleTriggeredEnchantmentCard,\r\n\tOnDespawnedEnchantmentCard,\r\n\tOnSpawnedEnchantmentCard,\r\n} from '../../card.interface';\r\n\r\nconst atkBuff = 1;\r\nconst healthBuff = 1;\r\n\r\n// We use the tagScriptDataNum2 to try and better handle the case where the minion is in hand - it starts\r\n// the combat with a certain value (stored in the tag), but it doesn't get increased as more deathrattles are triggered.\r\n// So when we summon it, we need to remove the stats from the tag (already processed) to not over-remove\r\nexport const DeathsEmbrace: DeathrattleTriggeredEnchantmentCard &\r\n\tOnSpawnedEnchantmentCard &\r\n\tOnDespawnedEnchantmentCard = {\r\n\tcardIds: [\r\n\t\tCardIds.DeathsEmbrace_DeathsEmbraceEnchantment_BG36_MidGameEffect_000t29te,\r\n\t\tCardIds.DeathsEmbrace_DeathsEmbraceEnchantment_BG36_MidGameEffect_000t29e,\r\n\t],\r\n\tonDeathrattleTriggeredEnchantment: (\r\n\t\tenchantedMinion: BoardEntity,\r\n\t\tenchantment: BoardEnchantment,\r\n\t\tinput: DeathrattleTriggeredInput,\r\n\t): BoardEntity[] => {\r\n\t\tconst mult =\r\n\t\t\tinput.deadEntity.cardId === CardIds.DeathsEmbrace_DeathsEmbraceEnchantment_BG36_MidGameEffect_000t29e\r\n\t\t\t\t? 2\r\n\t\t\t\t: 1;\r\n\t\tenchantedMinion.attack += mult * atkBuff;\r\n\t\tenchantedMinion.maxAttack += mult * atkBuff;\r\n\t\tenchantedMinion.health += mult * healthBuff;\r\n\t\tenchantedMinion.maxHealth += mult * healthBuff;\r\n\t\tenchantment.tagScriptDataNum2 += 1;\r\n\t\treturn [];\r\n\t},\r\n\t// I still have some doubts about whether, when spawned from hand, it really loses the existing enchantment, or if\r\n\t// it simply gains it again\r\n\tonSpawnedEnchantment: (minion: BoardEntity, enchantment: BoardEnchantment, input: OnSpawnInput) => {\r\n\t\tconst mult =\r\n\t\t\tenchantment.cardId === CardIds.DeathsEmbrace_DeathsEmbraceEnchantment_BG36_MidGameEffect_000t29e ? 2 : 1;\r\n\t\tconst base = input.hero.globalInfo.DeathrattlesTriggeredThisGame;\r\n\t\tif (input.applyAttackAuras) {\r\n\t\t\tminion.attack += mult * atkBuff * base;\r\n\t\t\tminion.maxAttack += mult * atkBuff * base;\r\n\t\t}\r\n\t\tif (input.applyHealthAuras) {\r\n\t\t\tminion.health += mult * healthBuff * base;\r\n\t\t\tminion.maxHealth += mult * healthBuff * base;\r\n\t\t}\r\n\t\tenchantment.tagScriptDataNum2 = base;\r\n\t},\r\n\tonDespawnedEnchantment: (minion: BoardEntity, enchantment: BoardEnchantment, input: OnDespawnInput) => {\r\n\t\tconst mult =\r\n\t\t\tenchantment.cardId === CardIds.DeathsEmbrace_DeathsEmbraceEnchantment_BG36_MidGameEffect_000t29e ? 2 : 1;\r\n\t\tconst base = enchantment.tagScriptDataNum2 ?? input.hero.globalInfo.DeathrattlesTriggeredThisGame;\r\n\t\tif (input.applyAttackAuras) {\r\n\t\t\tminion.attack -= mult * atkBuff * base;\r\n\t\t\tminion.maxAttack -= mult * atkBuff * base;\r\n\t\t}\r\n\t\tif (input.applyHealthAuras) {\r\n\t\t\tminion.health -= mult * healthBuff * base;\r\n\t\t\tminion.maxHealth -= mult * healthBuff * base;\r\n\t\t}\r\n\t},\r\n};\r\n"]}
|
|
@@ -11,7 +11,7 @@ exports.AllPurposeKibble = {
|
|
|
11
11
|
if (!(0, utils_1.hasCorrectTribe)(input.attacker, input.attackingHero, reference_data_1.Race.BEAST, input.gameState.anomalies, input.gameState.allCards)) {
|
|
12
12
|
return { dmgDoneByAttacker: 0, dmgDoneByDefender: 0 };
|
|
13
13
|
}
|
|
14
|
-
const buff =
|
|
14
|
+
const buff = trinket.scriptDataNum1 || 0;
|
|
15
15
|
(0, stats_1.modifyStats)(input.attacker, trinket, buff, 0, input.attackingBoard, input.attackingHero, input.gameState);
|
|
16
16
|
trinket.scriptDataNum1 = buff + attackBuff;
|
|
17
17
|
return { dmgDoneByAttacker: 0, dmgDoneByDefender: 0 };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"all-purpose-kibble.js","sourceRoot":"","sources":["../../../../src/cards/impl/trinket/all-purpose-kibble.ts"],"names":[],"mappings":";;;AAAA,iEAAoD;AAIpD,qDAAwD;AACxD,0CAAiD;AAGjD,MAAM,UAAU,GAAG,CAAC,CAAC;AAER,QAAA,gBAAgB,GAAuC;IACnE,OAAO,EAAE,sBAA6C;IACtD,8BAA8B,EAAE,CAAC,OAAqB,EAAE,KAAoB,EAAE,EAAE;QAC/E,IACC,CAAC,IAAA,uBAAe,EACf,KAAK,CAAC,QAAQ,EACd,KAAK,CAAC,aAAa,EACnB,qBAAI,CAAC,KAAK,EACV,KAAK,CAAC,SAAS,CAAC,SAAS,EACzB,KAAK,CAAC,SAAS,CAAC,QAAQ,CACxB,EACA;YACD,OAAO,EAAE,iBAAiB,EAAE,CAAC,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC;SACtD;QAED,MAAM,IAAI,GAAG,
|
|
1
|
+
{"version":3,"file":"all-purpose-kibble.js","sourceRoot":"","sources":["../../../../src/cards/impl/trinket/all-purpose-kibble.ts"],"names":[],"mappings":";;;AAAA,iEAAoD;AAIpD,qDAAwD;AACxD,0CAAiD;AAGjD,MAAM,UAAU,GAAG,CAAC,CAAC;AAER,QAAA,gBAAgB,GAAuC;IACnE,OAAO,EAAE,sBAA6C;IACtD,8BAA8B,EAAE,CAAC,OAAqB,EAAE,KAAoB,EAAE,EAAE;QAC/E,IACC,CAAC,IAAA,uBAAe,EACf,KAAK,CAAC,QAAQ,EACd,KAAK,CAAC,aAAa,EACnB,qBAAI,CAAC,KAAK,EACV,KAAK,CAAC,SAAS,CAAC,SAAS,EACzB,KAAK,CAAC,SAAS,CAAC,QAAQ,CACxB,EACA;YACD,OAAO,EAAE,iBAAiB,EAAE,CAAC,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC;SACtD;QAED,MAAM,IAAI,GAAG,OAAO,CAAC,cAAc,IAAI,CAAC,CAAC;QACzC,IAAA,mBAAW,EAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAC1G,OAAO,CAAC,cAAc,GAAG,IAAI,GAAG,UAAU,CAAC;QAC3C,OAAO,EAAE,iBAAiB,EAAE,CAAC,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC;IACvD,CAAC;CACD,CAAC","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\nimport { BoardTrinket } from '../../../bgs-player-entity';\r\nimport { CardIds } from '../../../services/card-ids';\r\nimport { OnAttackInput } from '../../../simulation/on-attack';\r\nimport { modifyStats } from '../../../simulation/stats';\r\nimport { hasCorrectTribe } from '../../../utils';\r\nimport { OnWheneverAnotherMinionAttacksCard } from '../../card.interface';\r\n\r\nconst attackBuff = 3;\r\n\r\nexport const AllPurposeKibble: OnWheneverAnotherMinionAttacksCard = {\r\n\tcardIds: [CardIds.AllPurposeKibble_BG32_MagicItem_200],\r\n\tonWheneverAnotherMinionAttacks: (trinket: BoardTrinket, input: OnAttackInput) => {\r\n\t\tif (\r\n\t\t\t!hasCorrectTribe(\r\n\t\t\t\tinput.attacker,\r\n\t\t\t\tinput.attackingHero,\r\n\t\t\t\tRace.BEAST,\r\n\t\t\t\tinput.gameState.anomalies,\r\n\t\t\t\tinput.gameState.allCards,\r\n\t\t\t)\r\n\t\t) {\r\n\t\t\treturn { dmgDoneByAttacker: 0, dmgDoneByDefender: 0 };\r\n\t\t}\r\n\r\n\t\tconst buff = trinket.scriptDataNum1 || 0;\r\n\t\tmodifyStats(input.attacker, trinket, buff, 0, input.attackingBoard, input.attackingHero, input.gameState);\r\n\t\ttrinket.scriptDataNum1 = buff + attackBuff;\r\n\t\treturn { dmgDoneByAttacker: 0, dmgDoneByDefender: 0 };\r\n\t},\r\n};\r\n"]}
|
|
@@ -15,7 +15,10 @@ exports.HeraldSticker = {
|
|
|
15
15
|
const indexFromRight = board.length - (board.indexOf(entity) + 1);
|
|
16
16
|
(0, deathrattle_orchestration_1.processDeathrattleForMinion)(entity, indexFromRight, [entity], entity.friendly ? input.gameState.gameState.player : input.gameState.gameState.opponent, entity.friendly ? input.gameState.gameState.opponent : input.gameState.gameState.player, input.gameState, false);
|
|
17
17
|
}
|
|
18
|
-
return
|
|
18
|
+
return {
|
|
19
|
+
hasTriggered: true,
|
|
20
|
+
shouldRecomputeCurrentAttacker: true,
|
|
21
|
+
};
|
|
19
22
|
},
|
|
20
23
|
};
|
|
21
24
|
//# sourceMappingURL=herald-sticker.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"herald-sticker.js","sourceRoot":"","sources":["../../../../src/cards/impl/trinket/herald-sticker.ts"],"names":[],"mappings":";;;AAEA,6FAA4F;AAC5F,6EAA6E;AAIhE,QAAA,aAAa,GAAsB;IAC/C,OAAO,EAAE,sBAA0C;IACnD,aAAa,EAAE,CAAC,OAAqB,EAAE,KAAe,EAAE,EAAE;QACzD,MAAM,UAAU,GAAG,IAAA,wCAAoB,EAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAChG,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE;YAChC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,mBAAmB,CAC5C,OAAO,EACP,MAAM,EACN,KAAK,CAAC,WAAW,EACjB,KAAK,CAAC,YAAY,EAClB,KAAK,CAAC,cAAc,CACpB,CAAC;YACF,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ;gBAC5B,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK;gBACxC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;YAC5C,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAClE,IAAA,uDAA2B,EAC1B,MAAM,EACN,cAAc,EACd,CAAC,MAAM,CAAC,EACR,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,EACvF,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,EACvF,KAAK,CAAC,SAAS,EACf,KAAK,CACL,CAAC;SACF;QACD,OAAO,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"herald-sticker.js","sourceRoot":"","sources":["../../../../src/cards/impl/trinket/herald-sticker.ts"],"names":[],"mappings":";;;AAEA,6FAA4F;AAC5F,6EAA6E;AAIhE,QAAA,aAAa,GAAsB;IAC/C,OAAO,EAAE,sBAA0C;IACnD,aAAa,EAAE,CAAC,OAAqB,EAAE,KAAe,EAAE,EAAE;QACzD,MAAM,UAAU,GAAG,IAAA,wCAAoB,EAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAChG,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE;YAChC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,mBAAmB,CAC5C,OAAO,EACP,MAAM,EACN,KAAK,CAAC,WAAW,EACjB,KAAK,CAAC,YAAY,EAClB,KAAK,CAAC,cAAc,CACpB,CAAC;YACF,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ;gBAC5B,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK;gBACxC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;YAC5C,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAClE,IAAA,uDAA2B,EAC1B,MAAM,EACN,cAAc,EACd,CAAC,MAAM,CAAC,EACR,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,EACvF,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,EACvF,KAAK,CAAC,SAAS,EACf,KAAK,CACL,CAAC;SACF;QACD,OAAO;YACN,YAAY,EAAE,IAAI;YAElB,8BAA8B,EAAE,IAAI;SACpC,CAAC;IACH,CAAC;CACD,CAAC","sourcesContent":["import { BoardTrinket } from '../../../bgs-player-entity';\r\nimport { CardIds } from '../../../services/card-ids';\r\nimport { processDeathrattleForMinion } from '../../../simulation/deathrattle-orchestration';\r\nimport { getValidDeathrattles } from '../../../simulation/deathrattle-utils';\r\nimport { SoCInput } from '../../../simulation/start-of-combat/start-of-combat-input';\r\nimport { StartOfCombatCard } from '../../card.interface';\r\n\r\nexport const HeraldSticker: StartOfCombatCard = {\r\n\tcardIds: [CardIds.HeraldSticker_BG32_MagicItem_306],\r\n\tstartOfCombat: (trinket: BoardTrinket, input: SoCInput) => {\r\n\t\tconst candidates = getValidDeathrattles(input.playerBoard, input.playerEntity, input.gameState);\r\n\t\tfor (const entity of candidates) {\r\n\t\t\tinput.gameState.spectator.registerPowerTarget(\r\n\t\t\t\ttrinket,\r\n\t\t\t\tentity,\r\n\t\t\t\tinput.playerBoard,\r\n\t\t\t\tinput.playerEntity,\r\n\t\t\t\tinput.opponentEntity,\r\n\t\t\t);\r\n\t\t\tconst board = entity.friendly\r\n\t\t\t\t? input.gameState.gameState.player.board\r\n\t\t\t\t: input.gameState.gameState.opponent.board;\r\n\t\t\tconst indexFromRight = board.length - (board.indexOf(entity) + 1);\r\n\t\t\tprocessDeathrattleForMinion(\r\n\t\t\t\tentity,\r\n\t\t\t\tindexFromRight,\r\n\t\t\t\t[entity],\r\n\t\t\t\tentity.friendly ? input.gameState.gameState.player : input.gameState.gameState.opponent,\r\n\t\t\t\tentity.friendly ? input.gameState.gameState.opponent : input.gameState.gameState.player,\r\n\t\t\t\tinput.gameState,\r\n\t\t\t\tfalse,\r\n\t\t\t);\r\n\t\t}\r\n\t\treturn {\r\n\t\t\thasTriggered: true,\r\n\t\t\t// https://replays.firestoneapp.com/?reviewId=e652bbdc-356f-4536-9e8f-086d525dc4e8&turn=21&action=2\r\n\t\t\tshouldRecomputeCurrentAttacker: true,\r\n\t\t};\r\n\t},\r\n};\r\n"]}
|
|
@@ -6,14 +6,17 @@ const stats_1 = require("../../../simulation/stats");
|
|
|
6
6
|
exports.TrainingCertificate = {
|
|
7
7
|
startOfCombat: (trinket, input) => {
|
|
8
8
|
if (input.playerBoard.length > 0) {
|
|
9
|
+
const updateStats = (entity) => {
|
|
10
|
+
(0, stats_1.modifyStats)(entity, trinket, entity.maxAttack, entity.maxHealth, input.playerBoard, input.playerEntity, input.gameState);
|
|
11
|
+
};
|
|
9
12
|
const baseBoard = (0, utils_1.shuffleArray)([...input.playerBoard]);
|
|
10
13
|
const minionsByAttack = baseBoard.sort((a, b) => a.attack - b.attack);
|
|
11
14
|
const firstTarget = minionsByAttack[0];
|
|
12
|
-
(
|
|
15
|
+
updateStats(firstTarget);
|
|
13
16
|
input.gameState.spectator.registerPowerTarget(trinket, firstTarget, input.playerBoard, null, null);
|
|
14
17
|
if (baseBoard.length > 1) {
|
|
15
18
|
const secondTarget = minionsByAttack[1];
|
|
16
|
-
(
|
|
19
|
+
updateStats(secondTarget);
|
|
17
20
|
input.gameState.spectator.registerPowerTarget(trinket, secondTarget, input.playerBoard, null, null);
|
|
18
21
|
}
|
|
19
22
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"training-certificate.js","sourceRoot":"","sources":["../../../../src/cards/impl/trinket/training-certificate.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"training-certificate.js","sourceRoot":"","sources":["../../../../src/cards/impl/trinket/training-certificate.ts"],"names":[],"mappings":";;;AAEA,mDAAuD;AAEvD,qDAAwD;AAE3C,QAAA,mBAAmB,GAAG;IAClC,aAAa,EAAE,CAAC,OAAqB,EAAE,KAAe,EAAE,EAAE;QACzD,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE;YAIjC,MAAM,WAAW,GAAG,CAAC,MAAmB,EAAE,EAAE;gBAC3C,IAAA,mBAAW,EACV,MAAM,EACN,OAAO,EACP,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,SAAS,EAChB,KAAK,CAAC,WAAW,EACjB,KAAK,CAAC,YAAY,EAClB,KAAK,CAAC,SAAS,CACf,CAAC;YASH,CAAC,CAAC;YAEF,MAAM,SAAS,GAAG,IAAA,oBAAY,EAAC,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;YACvD,MAAM,eAAe,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;YACtE,MAAM,WAAW,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;YACvC,WAAW,CAAC,WAAW,CAAC,CAAC;YACzB,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YACnG,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;gBACzB,MAAM,YAAY,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;gBACxC,WAAW,CAAC,YAAY,CAAC,CAAC;gBAC1B,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,mBAAmB,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;aACpG;YACD,OAAO,IAAI,CAAC;SACZ;IACF,CAAC;CACD,CAAC","sourcesContent":["import { BoardTrinket } from '../../../bgs-player-entity';\r\nimport { BoardEntity } from '../../../board-entity';\r\nimport { shuffleArray } from '../../../services/utils';\r\nimport { SoCInput } from '../../../simulation/start-of-combat/start-of-combat-input';\r\nimport { modifyStats } from '../../../simulation/stats';\r\n\r\nexport const TrainingCertificate = {\r\n\tstartOfCombat: (trinket: BoardTrinket, input: SoCInput) => {\r\n\t\tif (input.playerBoard.length > 0) {\r\n\t\t\t// It looks like it is a stats gain here?\r\n\t\t\t// https://replays.firestoneapp.com/?reviewId=7fb546a1-fd85-4006-bb8d-a4d6741bc6c4&turn=23&action=1\r\n\t\t\t// Not sure if that's a stats gain, or the way Tarecgosa works with setEntityStats\r\n\t\t\tconst updateStats = (entity: BoardEntity) => {\r\n\t\t\t\tmodifyStats(\r\n\t\t\t\t\tentity,\r\n\t\t\t\t\ttrinket,\r\n\t\t\t\t\tentity.maxAttack,\r\n\t\t\t\t\tentity.maxHealth,\r\n\t\t\t\t\tinput.playerBoard,\r\n\t\t\t\t\tinput.playerEntity,\r\n\t\t\t\t\tinput.gameState,\r\n\t\t\t\t);\r\n\t\t\t\t// setEntityStats(\r\n\t\t\t\t// \tentity,\r\n\t\t\t\t// \t2 * entity.maxAttack,\r\n\t\t\t\t// \t2 * entity.maxHealth,\r\n\t\t\t\t// \tinput.playerBoard,\r\n\t\t\t\t// \tinput.playerEntity,\r\n\t\t\t\t// \tinput.gameState,\r\n\t\t\t\t// );\r\n\t\t\t};\r\n\t\t\t// In cae of ties, it should be random\r\n\t\t\tconst baseBoard = shuffleArray([...input.playerBoard]);\r\n\t\t\tconst minionsByAttack = baseBoard.sort((a, b) => a.attack - b.attack);\r\n\t\t\tconst firstTarget = minionsByAttack[0];\r\n\t\t\tupdateStats(firstTarget);\r\n\t\t\tinput.gameState.spectator.registerPowerTarget(trinket, firstTarget, input.playerBoard, null, null);\r\n\t\t\tif (baseBoard.length > 1) {\r\n\t\t\t\tconst secondTarget = minionsByAttack[1];\r\n\t\t\t\tupdateStats(secondTarget);\r\n\t\t\t\tinput.gameState.spectator.registerPowerTarget(trinket, secondTarget, input.playerBoard, null, null);\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\t},\r\n};\r\n"]}
|
|
@@ -4,12 +4,12 @@ import { CardsData } from './cards/cards-data';
|
|
|
4
4
|
import { Rng } from './services/rng';
|
|
5
5
|
import { SimulationResult } from './simulation-result';
|
|
6
6
|
import { SingleSimulationResult } from './single-simulation-result';
|
|
7
|
-
export { isValidDeathrattleEnchantment } from './simulation/deathrattle-utils';
|
|
8
7
|
export { createSeededRng, defaultRng, getActiveRng, random, withRng } from './services/rng';
|
|
9
8
|
export type { Rng } from './services/rng';
|
|
10
|
-
export {
|
|
9
|
+
export { isValidDeathrattleEnchantment } from './simulation/deathrattle-utils';
|
|
11
10
|
export { hasRally } from './cards/card.interface';
|
|
12
11
|
export type { RallyCard } from './cards/card.interface';
|
|
12
|
+
export { triggerRally } from './mechanics/rally';
|
|
13
13
|
export type { OnAttackInput } from './simulation/on-attack';
|
|
14
14
|
export { triggerBattlecry } from './simulation/battlecries';
|
|
15
15
|
export { doFullAttack } from './simulation/attack';
|
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.simulateBattle = exports.simulateSingleCombat = exports.assignCards = exports.ensureCardsLoaded = exports.applyOnAttackEffects = exports.doFullAttack = exports.triggerBattlecry = exports.hasRally = exports.
|
|
3
|
+
exports.simulateBattle = exports.simulateSingleCombat = exports.assignCards = exports.ensureCardsLoaded = exports.applyOnAttackEffects = exports.doFullAttack = exports.triggerBattlecry = exports.triggerRally = exports.hasRally = exports.isValidDeathrattleEnchantment = exports.withRng = exports.random = exports.getActiveRng = exports.defaultRng = exports.createSeededRng = void 0;
|
|
4
4
|
const reference_data_1 = require("@firestone-hs/reference-data");
|
|
5
5
|
const cards_data_1 = require("./cards/cards-data");
|
|
6
6
|
const debug_state_1 = require("./debug-state");
|
|
7
7
|
const input_clone_1 = require("./input-clone");
|
|
8
8
|
const input_sanitation_1 = require("./input-sanitation");
|
|
9
9
|
const rng_1 = require("./services/rng");
|
|
10
|
+
const utils_1 = require("./services/utils");
|
|
11
|
+
const combat_profile_1 = require("./simulation/combat-profile");
|
|
10
12
|
const shared_state_1 = require("./simulation/shared-state");
|
|
11
13
|
const simulator_1 = require("./simulation/simulator");
|
|
12
14
|
const spectator_1 = require("./simulation/spectator/spectator");
|
|
13
|
-
const combat_profile_1 = require("./simulation/combat-profile");
|
|
14
|
-
const utils_1 = require("./services/utils");
|
|
15
|
-
var deathrattle_utils_1 = require("./simulation/deathrattle-utils");
|
|
16
|
-
Object.defineProperty(exports, "isValidDeathrattleEnchantment", { enumerable: true, get: function () { return deathrattle_utils_1.isValidDeathrattleEnchantment; } });
|
|
17
15
|
var rng_2 = require("./services/rng");
|
|
18
16
|
Object.defineProperty(exports, "createSeededRng", { enumerable: true, get: function () { return rng_2.createSeededRng; } });
|
|
19
17
|
Object.defineProperty(exports, "defaultRng", { enumerable: true, get: function () { return rng_2.defaultRng; } });
|
|
20
18
|
Object.defineProperty(exports, "getActiveRng", { enumerable: true, get: function () { return rng_2.getActiveRng; } });
|
|
21
19
|
Object.defineProperty(exports, "random", { enumerable: true, get: function () { return rng_2.random; } });
|
|
22
20
|
Object.defineProperty(exports, "withRng", { enumerable: true, get: function () { return rng_2.withRng; } });
|
|
23
|
-
var
|
|
24
|
-
Object.defineProperty(exports, "
|
|
21
|
+
var deathrattle_utils_1 = require("./simulation/deathrattle-utils");
|
|
22
|
+
Object.defineProperty(exports, "isValidDeathrattleEnchantment", { enumerable: true, get: function () { return deathrattle_utils_1.isValidDeathrattleEnchantment; } });
|
|
25
23
|
var card_interface_1 = require("./cards/card.interface");
|
|
26
24
|
Object.defineProperty(exports, "hasRally", { enumerable: true, get: function () { return card_interface_1.hasRally; } });
|
|
25
|
+
var rally_1 = require("./mechanics/rally");
|
|
26
|
+
Object.defineProperty(exports, "triggerRally", { enumerable: true, get: function () { return rally_1.triggerRally; } });
|
|
27
27
|
var battlecries_1 = require("./simulation/battlecries");
|
|
28
28
|
Object.defineProperty(exports, "triggerBattlecry", { enumerable: true, get: function () { return battlecries_1.triggerBattlecry; } });
|
|
29
29
|
var attack_1 = require("./simulation/attack");
|
|
@@ -342,17 +342,18 @@ const runSingleBattle = (cloneTemplate, cards, cardsData, spectator, rng) => {
|
|
|
342
342
|
return simulator.simulateSingleBattle(gameState.gameState.player, gameState.gameState.opponent);
|
|
343
343
|
};
|
|
344
344
|
const applyDebugStateFromInput = (battleInput) => {
|
|
345
|
-
var _a;
|
|
345
|
+
var _a, _b, _c;
|
|
346
346
|
if (!battleInput.debugState) {
|
|
347
347
|
return;
|
|
348
348
|
}
|
|
349
349
|
debug_state_1.debugState.active = true;
|
|
350
350
|
debug_state_1.debugState.forcedCurrentAttacker = battleInput.debugState.forcedCurrentAttacker;
|
|
351
|
-
debug_state_1.debugState.forcedFaceOffBase =
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
351
|
+
debug_state_1.debugState.forcedFaceOffBase =
|
|
352
|
+
(_b = (_a = battleInput.debugState.forcedFaceOffBase) === null || _a === void 0 ? void 0 : _a.map((f) => ({
|
|
353
|
+
attacker: { ...f.attacker },
|
|
354
|
+
defender: { ...f.defender },
|
|
355
|
+
}))) !== null && _b !== void 0 ? _b : [];
|
|
356
|
+
const rawPicks = (_c = battleInput.debugState.forcedRandomPicks) !== null && _c !== void 0 ? _c : [];
|
|
356
357
|
debug_state_1.debugState.forcedRandomPicksBase = rawPicks.map((p) => ({
|
|
357
358
|
source: { ...p.source },
|
|
358
359
|
target: { ...p.target },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"simulate-bgs-battle.js","sourceRoot":"","sources":["../src/simulate-bgs-battle.ts"],"names":[],"mappings":";;;AACA,iEAA+D;AAE/D,mDAA+C;AAC/C,+CAA2C;AAC3C,+CAAiE;AACjE,yDAAqD;AACrD,wCAA2E;AAI3E,4DAAwD;AACxD,sDAAmD;AACnD,gEAA4E;AAC5E,gEAIqC;AACrC,4CAAyC;AAEzC,oEAA+E;AAAtE,kIAAA,6BAA6B,OAAA;AACtC,sCAA4F;AAAnF,sGAAA,eAAe,OAAA;AAAE,iGAAA,UAAU,OAAA;AAAE,mGAAA,YAAY,OAAA;AAAE,6FAAA,MAAM,OAAA;AAAE,8FAAA,OAAO,OAAA;AAGnE,2CAAiD;AAAxC,qGAAA,YAAY,OAAA;AACrB,yDAAkD;AAAzC,0GAAA,QAAQ,OAAA;AAIjB,wDAA4D;AAAnD,+GAAA,gBAAgB,OAAA;AAEzB,8CAAmD;AAA1C,sGAAA,YAAY,OAAA;AACrB,oDAA8D;AAArD,iHAAA,oBAAoB,OAAA;AAK7B,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAC9B,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B,IAAI,WAAW,GAAG,IAAI,gCAAe,EAAE,CAAC;AAExC,IAAI,gBAAgB,GAA4B,IAAI,CAAC;AAGrD,MAAM,eAAe,GAAG,IAAI,OAAO,EAAU,CAAC;AAE9C,MAAM,cAAc,GAAG,CAAC,KAAyC,EAAW,EAAE;;IAC7E,IAAI,CAAC,KAAK,EAAE;QACX,OAAO,KAAK,CAAC;KACb;IACD,IAAI,eAAe,CAAC,GAAG,CAAC,KAAe,CAAC,EAAE;QACzC,OAAO,IAAI,CAAC;KACZ;IAED,MAAM,KAAK,GAAG,MAAA,KAAK,CAAC,OAAO,sDAAG,SAAS,CAAC,CAAC;IACzC,IAAI,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,EAAE,EAAE;QACd,eAAe,CAAC,GAAG,CAAC,KAAe,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC;KACZ;IACD,MAAM,MAAM,GAAG,CAAC,CAAC,CAAA,MAAA,MAAA,KAAK,CAAC,QAAQ,qDAAI,0CAAE,MAAM,CAAA,CAAC;IAC5C,IAAI,MAAM,EAAE;QACX,eAAe,CAAC,GAAG,CAAC,KAAe,CAAC,CAAC;KACrC;IACD,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,KAAK,EAAE,KAAsB,EAAoB,EAAE;IAC7E,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,mBAAmB,EAAE,OAAO,EAAE,EAAE;QAChE,IAAI;YACH,MAAM,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAChC,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE;gBAC1B,OAAO,IAAI,CAAC;aACZ;YACD,OAAO,CAAC,IAAI,CAAC,iEAAiE,EAAE,OAAO,CAAC,CAAC;SACzF;QAAC,OAAO,CAAC,EAAE;YACX,OAAO,CAAC,IAAI,CAAC,iDAAiD,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;SAC5E;QACD,IAAI,OAAO,GAAG,mBAAmB,EAAE;YAClC,MAAM,IAAA,aAAK,EAAC,GAAG,GAAG,OAAO,CAAC,CAAC;SAC3B;KACD;IACD,OAAO,KAAK,CAAC;AACd,CAAC,CAAC;AAMK,MAAM,iBAAiB,GAAG,KAAK,EAAE,QAAyB,WAAW,EAAoB,EAAE;IACjG,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE;QAC1B,OAAO,IAAI,CAAC;KACZ;IACD,IAAI,CAAC,gBAAgB,EAAE;QACtB,gBAAgB,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE;YACxD,IAAI,CAAC,EAAE,EAAE;gBAER,gBAAgB,GAAG,IAAI,CAAC;aACxB;YACD,OAAO,EAAE,CAAC;QACX,CAAC,CAAC,CAAC;KACH;IACD,OAAO,gBAAgB,CAAC;AACzB,CAAC,CAAC;AAdW,QAAA,iBAAiB,qBAc5B;AAEK,MAAM,WAAW,GAAG,CAAC,KAAsB,EAAE,EAAE;IACrD,WAAW,GAAG,KAAK,CAAC;IACpB,gBAAgB,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzE,CAAC,CAAC;AAHW,QAAA,WAAW,eAGtB;AAeK,MAAM,oBAAoB,GAAG,CACnC,WAA0B,EAC1B,KAAsB,EACtB,SAAoB,EACpB,UAAuC,EAAE,EAChB,EAAE;;IAC3B,MAAM,OAAO,GAAG,IAAA,qCAAoB,GAAE,CAAC;IACvC,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE;QAC3B,OAAO,CAAC,KAAK,CAAC,yEAAyE,EAAE,KAAK,CAAC,CAAC;QAChG,OAAO,IAAI,CAAC;KACZ;IACD,IAAI,OAAO,EAAE;QACZ,IAAA,iCAAgB,EAAC,YAAY,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,CAAC;KAC/D;IAED,MAAM,GAAG,GAAG,MAAA,OAAO,CAAC,GAAG,mCAAI,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAA,qBAAe,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,gBAAU,CAAC,CAAC;IACrG,MAAM,gBAAgB,GAAG,MAAA,OAAO,CAAC,gBAAgB,mCAAI,KAAK,CAAC;IAE3D,wBAAwB,CAAC,WAAW,CAAC,CAAC;IACtC,IAAI;QACH,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,MAAM,UAAU,GAAG,IAAA,kCAAe,EAAC,WAAW,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QAClE,IAAI,OAAO,EAAE;YACZ,IAAA,iCAAgB,EAAC,mBAAmB,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC;SACnE;QAGD,MAAM,aAAa,GAAG,GAAG,EAAE;YAC1B,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAChD,MAAM,MAAM,GAAG,IAAA,yBAAW,EAAC,UAAU,CAAC,CAAC;YACvC,IAAI,OAAO,EAAE;gBACZ,IAAA,iCAAgB,EAAC,SAAS,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC;aACzD;YACD,OAAO,MAAM,CAAC;QACf,CAAC,CAAC;QACF,MAAM,SAAS,GAAG,gBAAgB,CAAC,CAAC,CAAC,IAAI,qBAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,yBAAa,CAAC;QACzE,IAAI,gBAAgB,EAAE;YACrB,SAAS,CAAC,cAAc,EAAE,CAAC;SAC3B;QACD,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAA,aAAO,EAAC,GAAG,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;QACpG,IAAI,OAAO,EAAE;YACZ,IAAA,iCAAgB,EAAC,aAAa,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC;YAC3D,IAAA,uCAAsB,GAAE,CAAC;SACzB;QACD,OAAO,MAAM,CAAC;KACd;YAAS;QACT,wBAAwB,CAAC,WAAW,CAAC,CAAC;KACtC;AACF,CAAC,CAAC;AAlDW,QAAA,oBAAoB,wBAkD/B;AAKF,kBAAe,KAAK,EAAE,KAAK,EAAgB,EAAE;;IAC5C,IAAI,CAAC,CAAA,MAAA,KAAK,CAAC,IAAI,0CAAE,MAAM,CAAA,EAAE;QACxB,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;QAC1C,OAAO;YACN,UAAU,EAAE,GAAG;YACf,eAAe,EAAE,KAAK;YACtB,IAAI,EAAE,IAAI;SACV,CAAC;KACF;IAED,MAAM,WAAW,GAAkB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,WAAW,CAAC;IAC1B,MAAM,WAAW,GAAG,MAAM,IAAA,yBAAiB,EAAC,KAAK,CAAC,CAAC;IACnD,IAAI,CAAC,WAAW,EAAE;QACjB,OAAO,CAAC,KAAK,CAAC,oEAAoE,CAAC,CAAC;QACpF,OAAO;YACN,UAAU,EAAE,GAAG;YACf,eAAe,EAAE,KAAK;YACtB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;SACpD,CAAC;KACF;IACD,MAAM,SAAS,GAAG,IAAI,sBAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC9C,SAAS,CAAC,YAAY,CACrB,MAAA,MAAA,WAAW,CAAC,SAAS,0CAAE,WAAW,mCAAI,MAAA,WAAW,CAAC,OAAO,0CAAE,WAAW,EACtE,MAAA,MAAA,WAAW,CAAC,SAAS,0CAAE,SAAS,mCAAI,EAAE,CACtC,CAAC;IACF,MAAM,cAAc,GAAG,IAAA,sBAAc,EAAC,WAAW,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IAGrE,IAAI,MAAM,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC;IACnC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE;QACpB,MAAM,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC;KAC/B;IAED,MAAM,gBAAgB,GAAG,MAAM,CAAC,KAAK,CAAC;IAGtC,MAAM,QAAQ,GAAG;QAChB,UAAU,EAAE,GAAG;QACf,eAAe,EAAE,KAAK;QACtB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC;KACtC,CAAC;IACF,OAAO,QAAQ,CAAC;AACjB,CAAC,CAAC;AAEK,MAAM,cAAc,GAAG,QAAQ,CAAC,EACtC,WAA0B,EAC1B,KAAsB,EACtB,SAAoB;;IAEpB,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE;QAC3B,OAAO,CAAC,KAAK,CAAC,yEAAyE,EAAE,KAAK,CAAC,CAAC;QAChG,OAAO,IAAI,CAAC;KACZ;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,qBAAqB,GAAG,CAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,qBAAqB,KAAI,IAAI,CAAC;IACjF,MAAM,gCAAgC,GAAG,MAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,gCAAgC,mCAAI,KAAK,CAAC;IACxG,MAAM,mBAAmB,GAAG,CAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,mBAAmB,KAAI,IAAI,CAAC;IAC7E,MAAM,iBAAiB,GAAG,MAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,mBAAmB,mCAAI,GAAG,CAAC;IAC1E,MAAM,gBAAgB,GAAG,MAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,gBAAgB,mCAAI,GAAG,CAAC;IACtE,MAAM,qBAAqB,GAAG,MAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,qBAAqB,mCAAI,IAAI,CAAC;IACjF,MAAM,gBAAgB,GAAqB;QAC1C,SAAS,EAAE,CAAC;QACZ,GAAG,EAAE,CAAC;QACN,IAAI,EAAE,CAAC;QACP,IAAI,EAAE,CAAC;QACP,UAAU,EAAE,CAAC;QACb,UAAU,EAAE,EAAE;QACd,SAAS,EAAE,CAAC;QACZ,cAAc,EAAE,IAAI;QACpB,WAAW,EAAE,EAAE;QACf,UAAU,EAAE,CAAC;QACb,eAAe,EAAE,IAAI;QACrB,gBAAgB,EAAE,SAAS;QAC3B,UAAU,EAAE,SAAS;QACrB,WAAW,EAAE,SAAS;QACtB,WAAW,EAAE,SAAS;QACtB,iBAAiB,EAAE,SAAS;QAC5B,gBAAgB,EAAE,SAAS;QAC3B,iBAAiB,EAAE,SAAS;KAC5B,CAAC;IAEF,MAAM,SAAS,GAAG,IAAI,qBAAS,CAAC,qBAAqB,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,IAAA,kCAAe,EAAC,WAAW,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IAElE,wBAAwB,CAAC,WAAW,CAAC,CAAC;IAOtC,MAAM,aAAa,GAAG,IAAA,iCAAmB,EAAC,IAAA,yBAAW,EAAC,UAAU,CAAC,CAAC,CAAC;IAEnE,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,eAAe,CAAC,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAU,CAAC,CAAC;IAE7F,IAAI;QACH,CAAC,CAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,YAAY,CAAA,IAAI,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACjE,MAAM,QAAQ,GAAG,EAAE,CAAC;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,mBAAmB,EAAE,CAAC,EAAE,EAAE;YAC7C,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC;YAC9B,IAAI,CAAC,YAAY,EAAE;gBAClB,SAAS;aACT;YACD,IAAI,YAAY,CAAC,MAAM,KAAK,KAAK,EAAE;gBAClC,gBAAgB,CAAC,GAAG,EAAE,CAAC;gBACvB,gBAAgB,CAAC,SAAS,IAAI,YAAY,CAAC,WAAW,CAAC;gBACvD,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;gBAC3D,IAAI,YAAY,CAAC,WAAW,IAAI,WAAW,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE;oBACxE,gBAAgB,CAAC,SAAS,EAAE,CAAC;iBAC7B;aACD;iBAAM,IAAI,YAAY,CAAC,MAAM,KAAK,MAAM,EAAE;gBAC1C,gBAAgB,CAAC,IAAI,EAAE,CAAC;gBACxB,gBAAgB,CAAC,UAAU,IAAI,YAAY,CAAC,WAAW,CAAC;gBACxD,gBAAgB,CAAC,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;gBAC5D,QAAQ,CAAC,YAAY,CAAC,WAAW,CAAC,GAAG,CAAC,MAAA,QAAQ,CAAC,YAAY,CAAC,WAAW,CAAC,mCAAI,CAAC,CAAC,GAAG,CAAC,CAAC;gBACnF,IACC,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM;oBACrC,YAAY,CAAC,WAAW,IAAI,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAChE;oBACD,gBAAgB,CAAC,UAAU,EAAE,CAAC;iBAC9B;aACD;iBAAM,IAAI,YAAY,CAAC,MAAM,KAAK,MAAM,EAAE;gBAC1C,gBAAgB,CAAC,IAAI,EAAE,CAAC;aACxB;YAED,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,qBAAqB,IAAI,CAAC,gCAAgC,EAAE;gBAEpF,OAAO,CAAC,IAAI,CAAC,2BAA2B,EAAE,CAAC,EAAE,iBAAiB,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC;gBAC1F,MAAM;aACN;YAGD,IAAI,CAAC,CAAC,iBAAiB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,iBAAiB,KAAK,CAAC,EAAE;gBAChE,sBAAsB,CAAC,gBAAgB,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC;gBACvE,MAAM,gBAAgB,CAAC;aACvB;SACD;QACD,sBAAsB,CAAC,gBAAgB,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC;QACvE,CAAC,CAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,YAAY,CAAA,IAAI,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAOpE,IAAI,qBAAqB,EAAE;YAC1B,MAAM,cAAc,GAAgC,EAAE,CAAC;YACvD,gBAAgB,CAAC,GAAG,GAAG,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvD,gBAAgB,CAAC,IAAI,GAAG,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzD,gBAAgB,CAAC,IAAI,GAAG,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzD,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC;YAChD,IAAI,eAAe,CAAC,IAAI,GAAG,CAAC,EAAE;gBAC7B,SAAS,CAAC,cAAc,EAAE,CAAC;gBAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,iBAAiB,IAAI,eAAe,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;oBACvE,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC;oBAC9B,IAAI,CAAC,CAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,MAAM,CAAA,EAAE;wBAC1B,SAAS;qBACT;oBACD,SAAS,CAAC,kBAAkB,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;oBAClD,IAAI,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE;wBAChD,eAAe,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;qBAC5C;iBACD;gBACD,SAAS,CAAC,aAAa,EAAE,CAAC;aAC1B;SACD;QAED,SAAS,CAAC,KAAK,EAAE,CAAC;QAClB,gBAAgB,CAAC,cAAc,GAAG,SAAS,CAAC,mBAAmB,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QAGvF,gBAAgB,CAAC,UAAU,GAAG,EAAE,CAAC;QACjC,gBAAgB,CAAC,WAAW,GAAG,EAAE,CAAC;QAElC,OAAO,gBAAgB,CAAC;KACxB;YAAS;QACT,wBAAwB,CAAC,WAAW,CAAC,CAAC;KACtC;AACF,CAAC,CAAC;AAvIW,QAAA,cAAc,kBAuIzB;AAIF,MAAM,eAAe,GAAG,CACvB,aAA4B,EAC5B,KAAsB,EACtB,SAAoB,EACpB,SAAoB,EACpB,GAAQ,EACiB,EAAE;;IAC3B,MAAM,KAAK,GAAkB,aAAa,EAAE,CAAC;IAG7C,IAAI,kBAAkB,GAAG,IAAI,CAAC;IAC9B,IAAI,oBAAoB,GAAG,IAAI,CAAC;IAChC,MAAM,kBAAkB,GAAG,GAAG,EAAE;QAC/B,MAAM,UAAU,GAAkB,aAAa,EAAE,CAAC;QAClD,kBAAkB,GAAG;YACpB,MAAM,EAAE,UAAU,CAAC,WAAW,CAAC,MAAM;YACrC,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK;YACnC,QAAQ,EAAE,UAAU,CAAC,mBAAmB;SACxC,CAAC;QACF,oBAAoB,GAAG;YACtB,MAAM,EAAE,UAAU,CAAC,aAAa,CAAC,MAAM;YACvC,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,KAAK;YACrC,QAAQ,EAAE,UAAU,CAAC,qBAAqB;SAC1C,CAAC;IACH,CAAC,CAAC;IACF,MAAM,SAAS,GAAkB;QAChC,QAAQ,EAAE,KAAK;QACf,SAAS,EAAE,SAAS;QACpB,SAAS,EAAE,SAAS;QACpB,WAAW,EAAE,IAAI,0BAAW,CAAC,GAAG,CAAC;QACjC,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW;QACxC,oBAAoB,EAAE,KAAK,CAAC,SAAS,CAAC,oBAAoB;QAC1D,cAAc,EAAE,CAAA,MAAA,KAAK,CAAC,OAAO,0CAAE,cAAc,MAAK,IAAI;QACtD,aAAa,EAAE,CAAA,MAAA,KAAK,CAAC,OAAO,0CAAE,aAAa,MAAK,IAAI;QACpD,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,IAAI,CAAC,CAAC,KAAK,CAAC,qBAAqB;QACpE,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW;QACxC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS;QACpC,SAAS,EAAE;YACV,MAAM,EAAE;gBACP,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,MAAM;gBAChC,KAAK,EAAE,KAAK,CAAC,WAAW,CAAC,KAAK;gBAC9B,QAAQ,EAAE,KAAK,CAAC,mBAAmB;aACnC;YACD,QAAQ,EAAE;gBACT,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,MAAM;gBAClC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,KAAK;gBAChC,QAAQ,EAAE,KAAK,CAAC,qBAAqB;aACrC;YACD,IAAI,aAAa;gBAChB,IAAI,CAAC,kBAAkB,EAAE;oBACxB,kBAAkB,EAAE,CAAC;iBACrB;gBACD,OAAO,kBAAkB,CAAC;YAC3B,CAAC;YACD,IAAI,eAAe;gBAClB,IAAI,CAAC,oBAAoB,EAAE;oBAC1B,kBAAkB,EAAE,CAAC;iBACrB;gBACD,OAAO,oBAAoB,CAAC;YAC7B,CAAC;SACD;KACD,CAAC;IACF,MAAM,SAAS,GAAG,IAAI,qBAAS,CAAC,SAAS,CAAC,CAAC;IAC3C,OAAO,SAAS,CAAC,oBAAoB,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AACjG,CAAC,CAAC;AAEF,MAAM,wBAAwB,GAAG,CAAC,WAA0B,EAAE,EAAE;;IAC/D,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE;QAC5B,OAAO;KACP;IACD,wBAAU,CAAC,MAAM,GAAG,IAAI,CAAC;IACzB,wBAAU,CAAC,qBAAqB,GAAG,WAAW,CAAC,UAAU,CAAC,qBAAqB,CAAC;IAChF,wBAAU,CAAC,iBAAiB,GAAG,WAAW,CAAC,UAAU,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACnF,QAAQ,EAAE,EAAE,GAAG,CAAC,CAAC,QAAQ,EAAE;QAC3B,QAAQ,EAAE,EAAE,GAAG,CAAC,CAAC,QAAQ,EAAE;KAC3B,CAAC,CAAC,CAAC;IACJ,MAAM,QAAQ,GAAG,MAAA,WAAW,CAAC,UAAU,CAAC,iBAAiB,mCAAI,EAAE,CAAC;IAChE,wBAAU,CAAC,qBAAqB,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACvD,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE;QACvB,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE;QACvB,GAAG,CAAC,CAAC,CAAC,YAAY,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC;KACvD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,wBAAwB,GAAG,CAAC,WAA0B,EAAE,EAAE;IAC/D,IAAI,WAAW,CAAC,UAAU,EAAE;QAC3B,wBAAU,CAAC,MAAM,GAAG,KAAK,CAAC;KAC1B;AACF,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAAC,gBAAkC,EAAE,KAAoB,EAAE,gBAAwB,EAAE,EAAE;IACrH,MAAM,YAAY,GAAG,gBAAgB,CAAC,GAAG,GAAG,gBAAgB,CAAC,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;IAC1F,gBAAgB,CAAC,UAAU,GAAG,aAAa,CAC1C,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,EACnE,gBAAgB,CAAC,GAAG,EACpB,YAAY,CACZ,CAAC;IACF,gBAAgB,CAAC,gBAAgB,GAAG,aAAa,CAChD,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,EACzE,gBAAgB,CAAC,SAAS,EAC1B,YAAY,CACZ,CAAC;IACF,gBAAgB,CAAC,WAAW,GAAG,aAAa,CAC3C,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,EACpE,gBAAgB,CAAC,IAAI,EACrB,YAAY,CACZ,CAAC;IACF,gBAAgB,CAAC,iBAAiB,GAAG,aAAa,CACjD,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,EAC1E,gBAAgB,CAAC,UAAU,EAC3B,YAAY,CACZ,CAAC;IACF,gBAAgB,CAAC,WAAW,GAAG,aAAa,CAC3C,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,gBAAgB,CAAC,WAAW,GAAG,gBAAgB,CAAC,UAAU,CAAC,EAC7E,gBAAgB,CAAC,IAAI,EACrB,YAAY,CACZ,CAAC;IAIF,MAAM,cAAc,GAAG,gBAAgB,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9E,MAAM,eAAe,GAAG,gBAAgB,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAChF,MAAM,cAAc,GAAG,oBAAoB,CAAC,gBAAgB,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC;IAC3F,MAAM,eAAe,GAAG,oBAAoB,CAAC,gBAAgB,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;IAC7F,gBAAgB,CAAC,gBAAgB,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACrG,gBAAgB,CAAC,iBAAiB,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACzG,gBAAgB,CAAC,cAAc,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/E,gBAAgB,CAAC,eAAe,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC;IAElF,IACC,gBAAgB,CAAC,gBAAgB,GAAG,CAAC;QACrC,gBAAgB,CAAC,gBAAgB,GAAG,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,EACtE;QACD,OAAO,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;KACzC;IACD,IACC,gBAAgB,CAAC,iBAAiB,GAAG,CAAC;QACtC,gBAAgB,CAAC,iBAAiB,GAAG,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,EACzE;QACD,OAAO,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;KAC1C;AACF,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAAC,WAAqB,EAAE,gBAAwB,EAAgC,EAAE;IAC9G,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE;QAC7B,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;KAC1B;IAGD,MAAM,YAAY,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAG5D,MAAM,UAAU,GAAG,CAAC,GAAa,EAAE,CAAS,EAAE,EAAE;QAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;QACzC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,UAAU,CAAC,YAAY,EAAE,CAAC,GAAG,gBAAgB,CAAC,CAAC;IACjE,MAAM,SAAS,GAAG,UAAU,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;IAE7D,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,YAAoB,EAAE,YAAoB,EAAE,UAAkB,EAAU,EAAE;IAChG,IAAI,YAAY,KAAK,CAAC,IAAI,YAAY,KAAK,CAAC,EAAE;QAC7C,OAAO,IAAI,CAAC;KACZ;IACD,IAAI,YAAY,KAAK,GAAG,IAAI,YAAY,KAAK,UAAU,EAAE;QACxD,OAAO,IAAI,CAAC;KACZ;IACD,OAAO,YAAY,CAAC;AACrB,CAAC,CAAC","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport { BgsBattleInfo } from './bgs-battle-info';\r\nimport { CardsData } from './cards/cards-data';\r\nimport { debugState } from './debug-state';\r\nimport { buildTemplateCloner, cloneInput3 } from './input-clone';\r\nimport { buildFinalInput } from './input-sanitation';\r\nimport { createSeededRng, defaultRng, Rng, withRng } from './services/rng';\r\nimport { SimulationResult } from './simulation-result';\r\nimport { SingleSimulationResult } from './single-simulation-result';\r\nimport { FullGameState } from './simulation/internal-game-state';\r\nimport { SharedState } from './simulation/shared-state';\r\nimport { Simulator } from './simulation/simulator';\r\nimport { Spectator, noopSpectator } from './simulation/spectator/spectator';\r\nimport {\r\n\tcombatProfileAdd,\r\n\tcombatProfileEnabled,\r\n\tcombatProfileTickFight,\r\n} from './simulation/combat-profile';\r\nimport { sleep } from './services/utils';\r\n\r\nexport { isValidDeathrattleEnchantment } from './simulation/deathrattle-utils';\r\nexport { createSeededRng, defaultRng, getActiveRng, random, withRng } from './services/rng';\r\nexport type { Rng } from './services/rng';\r\n/** Tavern Activate / Hand of Deios-style Rally triggers (requires a combat FullGameState). */\r\nexport { triggerRally } from './mechanics/rally';\r\nexport { hasRally } from './cards/card.interface';\r\nexport type { RallyCard } from './cards/card.interface';\r\nexport type { OnAttackInput } from './simulation/on-attack';\r\n/** Tavern / Hand of Deios-style Battlecry re-triggers. */\r\nexport { triggerBattlecry } from './simulation/battlecries';\r\n/** Full attack resolution (on-attack, damage, after-attack, deaths) for tavern attacks e.g. Fishbait. */\r\nexport { doFullAttack } from './simulation/attack';\r\nexport { applyOnAttackEffects } from './simulation/on-attack';\r\n\r\n// Cap for the post-hoc outcome sample capture phase: rare outcomes (e.g. a 0.1% tie\r\n// chance) might never show up again when re-simulating, so we stop hunting after this\r\n// many extra battles\r\nconst MAX_SAMPLE_RESIMS = 500;\r\nconst CARDS_LOAD_ATTEMPTS = 3;\r\n\r\nlet globalCards = new AllCardsService();\r\n/** In-flight / completed cards init for this warm container (avoids re-fetch per invoke). */\r\nlet cardsInitPromise: Promise<boolean> | null = null;\r\n\r\n/** `getCards()` materializes the full DB (~14ms). Validate once per instance. */\r\nconst verifiedCardDbs = new WeakSet<object>();\r\n\r\nconst hasLoadedCards = (cards: AllCardsService | null | undefined): boolean => {\r\n\tif (!cards) {\r\n\t\treturn false;\r\n\t}\r\n\tif (verifiedCardDbs.has(cards as object)) {\r\n\t\treturn true;\r\n\t}\r\n\t// Prefer a single-card lookup. getCards() copies the whole DB (~14ms).\r\n\tconst probe = cards.getCard?.('CS2_122');\r\n\tif (probe?.id) {\r\n\t\tverifiedCardDbs.add(cards as object);\r\n\t\treturn true;\r\n\t}\r\n\tconst loaded = !!cards.getCards?.()?.length;\r\n\tif (loaded) {\r\n\t\tverifiedCardDbs.add(cards as object);\r\n\t}\r\n\treturn loaded;\r\n};\r\n\r\nconst loadCardsWithRetry = async (cards: AllCardsService): Promise<boolean> => {\r\n\tfor (let attempt = 1; attempt <= CARDS_LOAD_ATTEMPTS; attempt++) {\r\n\t\ttry {\r\n\t\t\tawait cards.initializeCardsDb();\r\n\t\t\tif (hasLoadedCards(cards)) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\tconsole.warn('[simulate-bgs-battle] cards still empty after initializeCardsDb', attempt);\r\n\t\t} catch (e) {\r\n\t\t\tconsole.warn('[simulate-bgs-battle] cards load attempt failed', attempt, e);\r\n\t\t}\r\n\t\tif (attempt < CARDS_LOAD_ATTEMPTS) {\r\n\t\t\tawait sleep(250 * attempt);\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n};\r\n\r\n/**\r\n * Load reference cards once per warm container. Retries transient CDN/fetch failures.\r\n * Returns false when cards could not be loaded after retries.\r\n */\r\nexport const ensureCardsLoaded = async (cards: AllCardsService = globalCards): Promise<boolean> => {\r\n\tif (hasLoadedCards(cards)) {\r\n\t\treturn true;\r\n\t}\r\n\tif (!cardsInitPromise) {\r\n\t\tcardsInitPromise = loadCardsWithRetry(cards).then((ok) => {\r\n\t\t\tif (!ok) {\r\n\t\t\t\t// Allow the next invoke to retry after a hard failure.\r\n\t\t\t\tcardsInitPromise = null;\r\n\t\t\t}\r\n\t\t\treturn ok;\r\n\t\t});\r\n\t}\r\n\treturn cardsInitPromise;\r\n};\r\n\r\nexport const assignCards = (cards: AllCardsService) => {\r\n\tglobalCards = cards;\r\n\tcardsInitPromise = hasLoadedCards(cards) ? Promise.resolve(true) : null;\r\n};\r\n\r\nexport interface SimulateSingleCombatOptions {\r\n\t/** If set, creates a Mulberry32 RNG from this seed. Ignored when `rng` is provided. */\r\n\treadonly seed?: number;\r\n\t/** Explicit RNG instance. Takes precedence over `seed`. */\r\n\treadonly rng?: Rng;\r\n\t/** When true, records spectator actions (slower). Default false. */\r\n\treadonly includeSpectator?: boolean;\r\n}\r\n\r\n/**\r\n * Run exactly one combat with a deterministic (or default) RNG.\r\n * Intended for the full-game / self-play env — not for Firestone win% Monte Carlo.\r\n */\r\nexport const simulateSingleCombat = (\r\n\tbattleInput: BgsBattleInfo,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n\toptions: SimulateSingleCombatOptions = {},\r\n): SingleSimulationResult => {\r\n\tconst profile = combatProfileEnabled();\r\n\tconst getCardsT0 = profile ? performance.now() : 0;\r\n\tif (!hasLoadedCards(cards)) {\r\n\t\tconsole.error('[simulate-bgs-battle] reference cards are empty, cannot simulate combat', cards);\r\n\t\treturn null;\r\n\t}\r\n\tif (profile) {\r\n\t\tcombatProfileAdd('getCardsMs', performance.now() - getCardsT0);\r\n\t}\r\n\r\n\tconst rng = options.rng ?? (options.seed !== undefined ? createSeededRng(options.seed) : defaultRng);\r\n\tconst includeSpectator = options.includeSpectator ?? false;\r\n\r\n\tapplyDebugStateFromInput(battleInput);\r\n\ttry {\r\n\t\tconst buildT0 = profile ? performance.now() : 0;\r\n\t\tconst inputReady = buildFinalInput(battleInput, cards, cardsData);\r\n\t\tif (profile) {\r\n\t\t\tcombatProfileAdd('buildFinalInputMs', performance.now() - buildT0);\r\n\t\t}\r\n\t\t// One fight: cloneInput3 per use (battle + optional initial-state snapshot).\r\n\t\t// Firestone Monte Carlo keeps buildTemplateCloner for 8000 sims.\r\n\t\tconst cloneTemplate = () => {\r\n\t\t\tconst cloneT0 = profile ? performance.now() : 0;\r\n\t\t\tconst cloned = cloneInput3(inputReady);\r\n\t\t\tif (profile) {\r\n\t\t\t\tcombatProfileAdd('cloneMs', performance.now() - cloneT0);\r\n\t\t\t}\r\n\t\t\treturn cloned;\r\n\t\t};\r\n\t\tconst spectator = includeSpectator ? new Spectator(true) : noopSpectator;\r\n\t\tif (includeSpectator) {\r\n\t\t\tspectator.startRecording();\r\n\t\t}\r\n\t\tconst runT0 = profile ? performance.now() : 0;\r\n\t\tconst result = withRng(rng, () => runSingleBattle(cloneTemplate, cards, cardsData, spectator, rng));\r\n\t\tif (profile) {\r\n\t\t\tcombatProfileAdd('runBattleMs', performance.now() - runT0);\r\n\t\t\tcombatProfileTickFight();\r\n\t\t}\r\n\t\treturn result;\r\n\t} finally {\r\n\t\tclearDebugStateFromInput(battleInput);\r\n\t}\r\n};\r\n\r\n// This example demonstrates a NodeJS 8.10 async handler[1], however of course you could use\r\n// the more traditional callback-style handler.\r\n// [1]: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/\r\nexport default async (event): Promise<any> => {\r\n\tif (!event.body?.length) {\r\n\t\tconsole.warn('missing event body', event);\r\n\t\treturn {\r\n\t\t\tstatusCode: 400,\r\n\t\t\tisBase64Encoded: false,\r\n\t\t\tbody: null,\r\n\t\t};\r\n\t}\r\n\r\n\tconst battleInput: BgsBattleInfo = JSON.parse(event.body);\r\n\tconst cards = globalCards;\r\n\tconst cardsLoaded = await ensureCardsLoaded(cards);\r\n\tif (!cardsLoaded) {\r\n\t\tconsole.error('[simulate-bgs-battle] failed to load reference cards after retries');\r\n\t\treturn {\r\n\t\t\tstatusCode: 503,\r\n\t\t\tisBase64Encoded: false,\r\n\t\t\tbody: JSON.stringify({ error: 'cards_unavailable' }),\r\n\t\t};\r\n\t}\r\n\tconst cardsData = new CardsData(cards, false);\r\n\tcardsData.inititialize(\r\n\t\tbattleInput.gameState?.validTribes ?? battleInput.options?.validTribes,\r\n\t\tbattleInput.gameState?.anomalies ?? [],\r\n\t);\r\n\tconst battleIterator = simulateBattle(battleInput, cards, cardsData);\r\n\r\n\t// Iterate through all intermediate results to reach the final result\r\n\tlet result = battleIterator.next();\r\n\twhile (!result.done) {\r\n\t\tresult = battleIterator.next();\r\n\t}\r\n\r\n\tconst simulationResult = result.value;\r\n\t// console.debug('simulationResult', simulationResult);\r\n\r\n\tconst response = {\r\n\t\tstatusCode: 200,\r\n\t\tisBase64Encoded: false,\r\n\t\tbody: JSON.stringify(simulationResult),\r\n\t};\r\n\treturn response;\r\n};\r\n\r\nexport const simulateBattle = function* (\r\n\tbattleInput: BgsBattleInfo,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n): Generator<SimulationResult, SimulationResult, void> {\r\n\tif (!hasLoadedCards(cards)) {\r\n\t\tconsole.error('[simulate-bgs-battle] reference cards are empty, cannot simulate battle', cards);\r\n\t\treturn null;\r\n\t}\r\n\t// !battleInput.options?.skipInfoLogs && console.time('full-sim');\r\n\tconst start = Date.now();\r\n\tconst maxAcceptableDuration = battleInput.options?.maxAcceptableDuration || 8000;\r\n\tconst hideMaxSimulationDurationWarning = battleInput.options?.hideMaxSimulationDurationWarning ?? false;\r\n\tconst numberOfSimulations = battleInput.options?.numberOfSimulations || 8000;\r\n\tconst intermediateSteps = battleInput.options?.intermediateResults ?? 200;\r\n\tconst damageConfidence = battleInput.options?.damageConfidence ?? 0.9;\r\n\tconst includeOutcomeSamples = battleInput.options?.includeOutcomeSamples ?? true;\r\n\tconst simulationResult: SimulationResult = {\r\n\t\twonLethal: 0,\r\n\t\twon: 0,\r\n\t\ttied: 0,\r\n\t\tlost: 0,\r\n\t\tlostLethal: 0,\r\n\t\tdamageWons: [],\r\n\t\tdamageWon: 0,\r\n\t\tdamageWonRange: null,\r\n\t\tdamageLosts: [],\r\n\t\tdamageLost: 0,\r\n\t\tdamageLostRange: null,\r\n\t\twonLethalPercent: undefined,\r\n\t\twonPercent: undefined,\r\n\t\ttiedPercent: undefined,\r\n\t\tlostPercent: undefined,\r\n\t\tlostLethalPercent: undefined,\r\n\t\taverageDamageWon: undefined,\r\n\t\taverageDamageLost: undefined,\r\n\t};\r\n\r\n\tconst spectator = new Spectator(includeOutcomeSamples);\r\n\tconst inputReady = buildFinalInput(battleInput, cards, cardsData);\r\n\r\n\tapplyDebugStateFromInput(battleInput);\r\n\r\n\t// cloneInput3 normalizes the input (sorted secrets, reset pendingAttackBuffs, etc.).\r\n\t// The compiled cloner re-materializes that normalized shape as an object literal, which is\r\n\t// faster than JSON.parse of a template string (~0.02ms vs ~0.12ms per clone on a 7v7\r\n\t// board), which was itself faster than generic recursive cloners (~0.19-0.23ms) and\r\n\t// structuredClone (~0.46ms)\r\n\tconst cloneTemplate = buildTemplateCloner(cloneInput3(inputReady));\r\n\r\n\tconst runOne = () => runSingleBattle(cloneTemplate, cards, cardsData, spectator, defaultRng);\r\n\r\n\ttry {\r\n\t\t!battleInput.options?.skipInfoLogs && console.time('simulation');\r\n\t\tconst outcomes = {};\r\n\t\tfor (let i = 0; i < numberOfSimulations; i++) {\r\n\t\t\tconst battleResult = runOne();\r\n\t\t\tif (!battleResult) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (battleResult.result === 'won') {\r\n\t\t\t\tsimulationResult.won++;\r\n\t\t\t\tsimulationResult.damageWon += battleResult.damageDealt;\r\n\t\t\t\tsimulationResult.damageWons.push(battleResult.damageDealt);\r\n\t\t\t\tif (battleResult.damageDealt >= battleInput.opponentBoard.player.hpLeft) {\r\n\t\t\t\t\tsimulationResult.wonLethal++;\r\n\t\t\t\t}\r\n\t\t\t} else if (battleResult.result === 'lost') {\r\n\t\t\t\tsimulationResult.lost++;\r\n\t\t\t\tsimulationResult.damageLost += battleResult.damageDealt;\r\n\t\t\t\tsimulationResult.damageLosts.push(battleResult.damageDealt);\r\n\t\t\t\toutcomes[battleResult.damageDealt] = (outcomes[battleResult.damageDealt] ?? 0) + 1;\r\n\t\t\t\tif (\r\n\t\t\t\t\tbattleInput.playerBoard.player.hpLeft &&\r\n\t\t\t\t\tbattleResult.damageDealt >= battleInput.playerBoard.player.hpLeft\r\n\t\t\t\t) {\r\n\t\t\t\t\tsimulationResult.lostLethal++;\r\n\t\t\t\t}\r\n\t\t\t} else if (battleResult.result === 'tied') {\r\n\t\t\t\tsimulationResult.tied++;\r\n\t\t\t}\r\n\r\n\t\t\tif (Date.now() - start > maxAcceptableDuration && !hideMaxSimulationDurationWarning) {\r\n\t\t\t\t// Can happen in case of inifinite boards, or a bug. Don't hog the user's computer in that case\r\n\t\t\t\tconsole.warn('Stopping simulation after', i, 'iterations and ', Date.now() - start, 'ms');\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\t// Yield intermediate result every 200 iterations\r\n\t\t\tif (!!intermediateSteps && i > 0 && i % intermediateSteps === 0) {\r\n\t\t\t\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\r\n\t\t\t\tyield simulationResult;\r\n\t\t\t}\r\n\t\t}\r\n\t\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\r\n\t\t!battleInput.options?.skipInfoLogs && console.timeEnd('simulation');\r\n\r\n\t\t// Capture outcome samples post-hoc: re-run a few battles with action recording turned\r\n\t\t// on, until each outcome that actually occurred has a sample. This is much cheaper\r\n\t\t// than recording during the main loop, where almost all recorded actions get discarded.\r\n\t\t// This phase intentionally ignores maxAcceptableDuration: when the main loop was cut\r\n\t\t// short by the time budget, we would otherwise end up with no samples at all.\r\n\t\tif (includeOutcomeSamples) {\r\n\t\t\tconst neededOutcomes: ('won' | 'lost' | 'tied')[] = [];\r\n\t\t\tsimulationResult.won > 0 && neededOutcomes.push('won');\r\n\t\t\tsimulationResult.lost > 0 && neededOutcomes.push('lost');\r\n\t\t\tsimulationResult.tied > 0 && neededOutcomes.push('tied');\r\n\t\t\tconst missingOutcomes = new Set(neededOutcomes);\r\n\t\t\tif (missingOutcomes.size > 0) {\r\n\t\t\t\tspectator.startRecording();\r\n\t\t\t\tfor (let i = 0; i < MAX_SAMPLE_RESIMS && missingOutcomes.size > 0; i++) {\r\n\t\t\t\t\tconst battleResult = runOne();\r\n\t\t\t\t\tif (!battleResult?.result) {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tspectator.commitBattleResult(battleResult.result);\r\n\t\t\t\t\tif (spectator.hasSampleFor(battleResult.result)) {\r\n\t\t\t\t\t\tmissingOutcomes.delete(battleResult.result);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tspectator.stopRecording();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tspectator.prune();\r\n\t\tsimulationResult.outcomeSamples = spectator.buildOutcomeSamples(battleInput.gameState);\r\n\t\t// Avoid sending this verbose data\r\n\r\n\t\tsimulationResult.damageWons = [];\r\n\t\tsimulationResult.damageLosts = [];\r\n\t\t// !battleInput.options?.skipInfoLogs && console.timeEnd('full-sim');\r\n\t\treturn simulationResult;\r\n\t} finally {\r\n\t\tclearDebugStateFromInput(battleInput);\r\n\t}\r\n};\r\n\r\ntype CloneTemplate = () => BgsBattleInfo;\r\n\r\nconst runSingleBattle = (\r\n\tcloneTemplate: CloneTemplate,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n\tspectator: Spectator,\r\n\trng: Rng,\r\n): SingleSimulationResult => {\r\n\tconst input: BgsBattleInfo = cloneTemplate();\r\n\t// The \"initial\" states are only read by a handful of cards (and mutated by some, like\r\n\t// San'layn Scribe), so we only pay for the second clone when they are actually accessed\r\n\tlet playerInitialState = null;\r\n\tlet opponentInitialState = null;\r\n\tconst buildInitialStates = () => {\r\n\t\tconst inputClone: BgsBattleInfo = cloneTemplate();\r\n\t\tplayerInitialState = {\r\n\t\t\tplayer: inputClone.playerBoard.player,\r\n\t\t\tboard: inputClone.playerBoard.board,\r\n\t\t\tteammate: inputClone.playerTeammateBoard,\r\n\t\t};\r\n\t\topponentInitialState = {\r\n\t\t\tplayer: inputClone.opponentBoard.player,\r\n\t\t\tboard: inputClone.opponentBoard.board,\r\n\t\t\tteammate: inputClone.opponentTeammateBoard,\r\n\t\t};\r\n\t};\r\n\tconst gameState: FullGameState = {\r\n\t\tallCards: cards,\r\n\t\tcardsData: cardsData,\r\n\t\tspectator: spectator,\r\n\t\tsharedState: new SharedState(rng),\r\n\t\tcurrentTurn: input.gameState.currentTurn,\r\n\t\tnumberOfPlayersAlive: input.gameState.numberOfPlayersAlive,\r\n\t\tapplyDamageCap: input.options?.applyDamageCap === true,\r\n\t\tapplyIceBlock: input.options?.applyIceBlock === true,\r\n\t\tisDuos: !!input.playerTeammateBoard || !!input.opponentTeammateBoard,\r\n\t\tvalidTribes: input.gameState.validTribes,\r\n\t\tanomalies: input.gameState.anomalies,\r\n\t\tgameState: {\r\n\t\t\tplayer: {\r\n\t\t\t\tplayer: input.playerBoard.player,\r\n\t\t\t\tboard: input.playerBoard.board,\r\n\t\t\t\tteammate: input.playerTeammateBoard,\r\n\t\t\t},\r\n\t\t\topponent: {\r\n\t\t\t\tplayer: input.opponentBoard.player,\r\n\t\t\t\tboard: input.opponentBoard.board,\r\n\t\t\t\tteammate: input.opponentTeammateBoard,\r\n\t\t\t},\r\n\t\t\tget playerInitial() {\r\n\t\t\t\tif (!playerInitialState) {\r\n\t\t\t\t\tbuildInitialStates();\r\n\t\t\t\t}\r\n\t\t\t\treturn playerInitialState;\r\n\t\t\t},\r\n\t\t\tget opponentInitial() {\r\n\t\t\t\tif (!opponentInitialState) {\r\n\t\t\t\t\tbuildInitialStates();\r\n\t\t\t\t}\r\n\t\t\t\treturn opponentInitialState;\r\n\t\t\t},\r\n\t\t},\r\n\t};\r\n\tconst simulator = new Simulator(gameState);\r\n\treturn simulator.simulateSingleBattle(gameState.gameState.player, gameState.gameState.opponent);\r\n};\r\n\r\nconst applyDebugStateFromInput = (battleInput: BgsBattleInfo) => {\r\n\tif (!battleInput.debugState) {\r\n\t\treturn;\r\n\t}\r\n\tdebugState.active = true;\r\n\tdebugState.forcedCurrentAttacker = battleInput.debugState.forcedCurrentAttacker;\r\n\tdebugState.forcedFaceOffBase = battleInput.debugState.forcedFaceOffBase.map((f) => ({\r\n\t\tattacker: { ...f.attacker },\r\n\t\tdefender: { ...f.defender },\r\n\t}));\r\n\tconst rawPicks = battleInput.debugState.forcedRandomPicks ?? [];\r\n\tdebugState.forcedRandomPicksBase = rawPicks.map((p) => ({\r\n\t\tsource: { ...p.source },\r\n\t\ttarget: { ...p.target },\r\n\t\t...(p.chosenCardId && { chosenCardId: p.chosenCardId }),\r\n\t}));\r\n};\r\n\r\nconst clearDebugStateFromInput = (battleInput: BgsBattleInfo) => {\r\n\tif (battleInput.debugState) {\r\n\t\tdebugState.active = false;\r\n\t}\r\n};\r\n\r\nconst updateSimulationResult = (simulationResult: SimulationResult, input: BgsBattleInfo, damageConfidence: number) => {\r\n\tconst totalMatches = simulationResult.won + simulationResult.tied + simulationResult.lost;\r\n\tsimulationResult.wonPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.won)) / totalMatches) / 10,\r\n\t\tsimulationResult.won,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.wonLethalPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10,\r\n\t\tsimulationResult.wonLethal,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.lostPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.lost)) / totalMatches) / 10,\r\n\t\tsimulationResult.lost,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.lostLethalPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10,\r\n\t\tsimulationResult.lostLethal,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.tiedPercent = checkRounding(\r\n\t\tMath.max(0, 100 - simulationResult.lostPercent - simulationResult.wonPercent),\r\n\t\tsimulationResult.tied,\r\n\t\ttotalMatches,\r\n\t);\r\n\r\n\t// simulationResult.wonLethalPercent = Math.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10;\r\n\t// simulationResult.lostLethalPercent = Math.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10;\r\n\tconst totalDamageWon = simulationResult.damageWons.reduce((a, b) => a + b, 0);\r\n\tconst totalDamageLost = simulationResult.damageLosts.reduce((a, b) => a + b, 0);\r\n\tconst damageWonRange = calculateDamageRange(simulationResult.damageWons, damageConfidence);\r\n\tconst damageLostRange = calculateDamageRange(simulationResult.damageLosts, damageConfidence);\r\n\tsimulationResult.averageDamageWon = simulationResult.won ? totalDamageWon / simulationResult.won : 0;\r\n\tsimulationResult.averageDamageLost = simulationResult.lost ? totalDamageLost / simulationResult.lost : 0;\r\n\tsimulationResult.damageWonRange = simulationResult.won ? damageWonRange : null;\r\n\tsimulationResult.damageLostRange = simulationResult.lost ? damageLostRange : null;\r\n\r\n\tif (\r\n\t\tsimulationResult.averageDamageWon > 0 &&\r\n\t\tsimulationResult.averageDamageWon < input.playerBoard.player.tavernTier\r\n\t) {\r\n\t\tconsole.warn('average damage won issue');\r\n\t}\r\n\tif (\r\n\t\tsimulationResult.averageDamageLost > 0 &&\r\n\t\tsimulationResult.averageDamageLost < input.opponentBoard.player.tavernTier\r\n\t) {\r\n\t\tconsole.warn('average damage lost issue');\r\n\t}\r\n};\r\n\r\nconst calculateDamageRange = (damageArray: number[], damageConfidence: number): { min: number; max: number } => {\r\n\tif (damageArray.length === 0) {\r\n\t\treturn { min: 0, max: 0 };\r\n\t}\r\n\r\n\t// Sort the array\r\n\tconst sortedDamage = [...damageArray].sort((a, b) => a - b);\r\n\r\n\t// Calculate the 10th and 90th percentiles\r\n\tconst percentile = (arr: number[], p: number) => {\r\n\t\tconst index = Math.floor(p * arr.length);\r\n\t\treturn arr[index];\r\n\t};\r\n\r\n\tconst minDamage = percentile(sortedDamage, 1 - damageConfidence);\r\n\tconst maxDamage = percentile(sortedDamage, damageConfidence);\r\n\r\n\treturn { min: minDamage, max: maxDamage };\r\n};\r\n\r\nconst checkRounding = (roundedValue: number, initialValue: number, totalValue: number): number => {\r\n\tif (roundedValue === 0 && initialValue !== 0) {\r\n\t\treturn 0.01;\r\n\t}\r\n\tif (roundedValue === 100 && initialValue !== totalValue) {\r\n\t\treturn 99.9;\r\n\t}\r\n\treturn roundedValue;\r\n};\r\n\r\n// const cleanEnchantmentsForEntity = (\r\n// \tenchantments: { cardId: string; originEntityId?: number; timing: number }[],\r\n// \tentityIds: readonly number[],\r\n// ): { cardId: string; originEntityId?: number; timing: number }[] => {\r\n// \treturn enchantments.filter(\r\n// \t\t(enchant) =>\r\n// \t\t\tentityIds.indexOf(enchant.originEntityId) !== -1 ||\r\n// \t\t\tvalidEnchantments.indexOf(enchant.cardId as CardIds) !== -1,\r\n// \t);\r\n// };\r\n"]}
|
|
1
|
+
{"version":3,"file":"simulate-bgs-battle.js","sourceRoot":"","sources":["../src/simulate-bgs-battle.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport { BgsBattleInfo } from './bgs-battle-info';\r\nimport { CardsData } from './cards/cards-data';\r\nimport { debugState } from './debug-state';\r\nimport { buildTemplateCloner, cloneInput3 } from './input-clone';\r\nimport { buildFinalInput } from './input-sanitation';\r\nimport { createSeededRng, defaultRng, Rng, withRng } from './services/rng';\r\nimport { sleep } from './services/utils';\r\nimport { SimulationResult } from './simulation-result';\r\nimport { combatProfileAdd, combatProfileEnabled, combatProfileTickFight } from './simulation/combat-profile';\r\nimport { FullGameState } from './simulation/internal-game-state';\r\nimport { SharedState } from './simulation/shared-state';\r\nimport { Simulator } from './simulation/simulator';\r\nimport { noopSpectator, Spectator } from './simulation/spectator/spectator';\r\nimport { SingleSimulationResult } from './single-simulation-result';\r\n\r\nexport { createSeededRng, defaultRng, getActiveRng, random, withRng } from './services/rng';\r\nexport type { Rng } from './services/rng';\r\nexport { isValidDeathrattleEnchantment } from './simulation/deathrattle-utils';\r\n/** Tavern Activate / Hand of Deios-style Rally triggers (requires a combat FullGameState). */\r\nexport { hasRally } from './cards/card.interface';\r\nexport type { RallyCard } from './cards/card.interface';\r\nexport { triggerRally } from './mechanics/rally';\r\nexport type { OnAttackInput } from './simulation/on-attack';\r\n/** Tavern / Hand of Deios-style Battlecry re-triggers. */\r\nexport { triggerBattlecry } from './simulation/battlecries';\r\n/** Full attack resolution (on-attack, damage, after-attack, deaths) for tavern attacks e.g. Fishbait. */\r\nexport { doFullAttack } from './simulation/attack';\r\nexport { applyOnAttackEffects } from './simulation/on-attack';\r\n\r\n// Cap for the post-hoc outcome sample capture phase: rare outcomes (e.g. a 0.1% tie\r\n// chance) might never show up again when re-simulating, so we stop hunting after this\r\n// many extra battles\r\nconst MAX_SAMPLE_RESIMS = 500;\r\nconst CARDS_LOAD_ATTEMPTS = 3;\r\n\r\nlet globalCards = new AllCardsService();\r\n/** In-flight / completed cards init for this warm container (avoids re-fetch per invoke). */\r\nlet cardsInitPromise: Promise<boolean> | null = null;\r\n\r\n/** `getCards()` materializes the full DB (~14ms). Validate once per instance. */\r\nconst verifiedCardDbs = new WeakSet<object>();\r\n\r\nconst hasLoadedCards = (cards: AllCardsService | null | undefined): boolean => {\r\n\tif (!cards) {\r\n\t\treturn false;\r\n\t}\r\n\tif (verifiedCardDbs.has(cards as object)) {\r\n\t\treturn true;\r\n\t}\r\n\t// Prefer a single-card lookup. getCards() copies the whole DB (~14ms).\r\n\tconst probe = cards.getCard?.('CS2_122');\r\n\tif (probe?.id) {\r\n\t\tverifiedCardDbs.add(cards as object);\r\n\t\treturn true;\r\n\t}\r\n\tconst loaded = !!cards.getCards?.()?.length;\r\n\tif (loaded) {\r\n\t\tverifiedCardDbs.add(cards as object);\r\n\t}\r\n\treturn loaded;\r\n};\r\n\r\nconst loadCardsWithRetry = async (cards: AllCardsService): Promise<boolean> => {\r\n\tfor (let attempt = 1; attempt <= CARDS_LOAD_ATTEMPTS; attempt++) {\r\n\t\ttry {\r\n\t\t\tawait cards.initializeCardsDb();\r\n\t\t\tif (hasLoadedCards(cards)) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\tconsole.warn('[simulate-bgs-battle] cards still empty after initializeCardsDb', attempt);\r\n\t\t} catch (e) {\r\n\t\t\tconsole.warn('[simulate-bgs-battle] cards load attempt failed', attempt, e);\r\n\t\t}\r\n\t\tif (attempt < CARDS_LOAD_ATTEMPTS) {\r\n\t\t\tawait sleep(250 * attempt);\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n};\r\n\r\n/**\r\n * Load reference cards once per warm container. Retries transient CDN/fetch failures.\r\n * Returns false when cards could not be loaded after retries.\r\n */\r\nexport const ensureCardsLoaded = async (cards: AllCardsService = globalCards): Promise<boolean> => {\r\n\tif (hasLoadedCards(cards)) {\r\n\t\treturn true;\r\n\t}\r\n\tif (!cardsInitPromise) {\r\n\t\tcardsInitPromise = loadCardsWithRetry(cards).then((ok) => {\r\n\t\t\tif (!ok) {\r\n\t\t\t\t// Allow the next invoke to retry after a hard failure.\r\n\t\t\t\tcardsInitPromise = null;\r\n\t\t\t}\r\n\t\t\treturn ok;\r\n\t\t});\r\n\t}\r\n\treturn cardsInitPromise;\r\n};\r\n\r\nexport const assignCards = (cards: AllCardsService) => {\r\n\tglobalCards = cards;\r\n\tcardsInitPromise = hasLoadedCards(cards) ? Promise.resolve(true) : null;\r\n};\r\n\r\nexport interface SimulateSingleCombatOptions {\r\n\t/** If set, creates a Mulberry32 RNG from this seed. Ignored when `rng` is provided. */\r\n\treadonly seed?: number;\r\n\t/** Explicit RNG instance. Takes precedence over `seed`. */\r\n\treadonly rng?: Rng;\r\n\t/** When true, records spectator actions (slower). Default false. */\r\n\treadonly includeSpectator?: boolean;\r\n}\r\n\r\n/**\r\n * Run exactly one combat with a deterministic (or default) RNG.\r\n * Intended for the full-game / self-play env — not for Firestone win% Monte Carlo.\r\n */\r\nexport const simulateSingleCombat = (\r\n\tbattleInput: BgsBattleInfo,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n\toptions: SimulateSingleCombatOptions = {},\r\n): SingleSimulationResult => {\r\n\tconst profile = combatProfileEnabled();\r\n\tconst getCardsT0 = profile ? performance.now() : 0;\r\n\tif (!hasLoadedCards(cards)) {\r\n\t\tconsole.error('[simulate-bgs-battle] reference cards are empty, cannot simulate combat', cards);\r\n\t\treturn null;\r\n\t}\r\n\tif (profile) {\r\n\t\tcombatProfileAdd('getCardsMs', performance.now() - getCardsT0);\r\n\t}\r\n\r\n\tconst rng = options.rng ?? (options.seed !== undefined ? createSeededRng(options.seed) : defaultRng);\r\n\tconst includeSpectator = options.includeSpectator ?? false;\r\n\r\n\tapplyDebugStateFromInput(battleInput);\r\n\ttry {\r\n\t\tconst buildT0 = profile ? performance.now() : 0;\r\n\t\tconst inputReady = buildFinalInput(battleInput, cards, cardsData);\r\n\t\tif (profile) {\r\n\t\t\tcombatProfileAdd('buildFinalInputMs', performance.now() - buildT0);\r\n\t\t}\r\n\t\t// One fight: cloneInput3 per use (battle + optional initial-state snapshot).\r\n\t\t// Firestone Monte Carlo keeps buildTemplateCloner for 8000 sims.\r\n\t\tconst cloneTemplate = () => {\r\n\t\t\tconst cloneT0 = profile ? performance.now() : 0;\r\n\t\t\tconst cloned = cloneInput3(inputReady);\r\n\t\t\tif (profile) {\r\n\t\t\t\tcombatProfileAdd('cloneMs', performance.now() - cloneT0);\r\n\t\t\t}\r\n\t\t\treturn cloned;\r\n\t\t};\r\n\t\tconst spectator = includeSpectator ? new Spectator(true) : noopSpectator;\r\n\t\tif (includeSpectator) {\r\n\t\t\tspectator.startRecording();\r\n\t\t}\r\n\t\tconst runT0 = profile ? performance.now() : 0;\r\n\t\tconst result = withRng(rng, () => runSingleBattle(cloneTemplate, cards, cardsData, spectator, rng));\r\n\t\tif (profile) {\r\n\t\t\tcombatProfileAdd('runBattleMs', performance.now() - runT0);\r\n\t\t\tcombatProfileTickFight();\r\n\t\t}\r\n\t\treturn result;\r\n\t} finally {\r\n\t\tclearDebugStateFromInput(battleInput);\r\n\t}\r\n};\r\n\r\n// This example demonstrates a NodeJS 8.10 async handler[1], however of course you could use\r\n// the more traditional callback-style handler.\r\n// [1]: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/\r\nexport default async (event): Promise<any> => {\r\n\tif (!event.body?.length) {\r\n\t\tconsole.warn('missing event body', event);\r\n\t\treturn {\r\n\t\t\tstatusCode: 400,\r\n\t\t\tisBase64Encoded: false,\r\n\t\t\tbody: null,\r\n\t\t};\r\n\t}\r\n\r\n\tconst battleInput: BgsBattleInfo = JSON.parse(event.body);\r\n\tconst cards = globalCards;\r\n\tconst cardsLoaded = await ensureCardsLoaded(cards);\r\n\tif (!cardsLoaded) {\r\n\t\tconsole.error('[simulate-bgs-battle] failed to load reference cards after retries');\r\n\t\treturn {\r\n\t\t\tstatusCode: 503,\r\n\t\t\tisBase64Encoded: false,\r\n\t\t\tbody: JSON.stringify({ error: 'cards_unavailable' }),\r\n\t\t};\r\n\t}\r\n\tconst cardsData = new CardsData(cards, false);\r\n\tcardsData.inititialize(\r\n\t\tbattleInput.gameState?.validTribes ?? battleInput.options?.validTribes,\r\n\t\tbattleInput.gameState?.anomalies ?? [],\r\n\t);\r\n\tconst battleIterator = simulateBattle(battleInput, cards, cardsData);\r\n\r\n\t// Iterate through all intermediate results to reach the final result\r\n\tlet result = battleIterator.next();\r\n\twhile (!result.done) {\r\n\t\tresult = battleIterator.next();\r\n\t}\r\n\r\n\tconst simulationResult = result.value;\r\n\t// console.debug('simulationResult', simulationResult);\r\n\r\n\tconst response = {\r\n\t\tstatusCode: 200,\r\n\t\tisBase64Encoded: false,\r\n\t\tbody: JSON.stringify(simulationResult),\r\n\t};\r\n\treturn response;\r\n};\r\n\r\nexport const simulateBattle = function* (\r\n\tbattleInput: BgsBattleInfo,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n): Generator<SimulationResult, SimulationResult, void> {\r\n\tif (!hasLoadedCards(cards)) {\r\n\t\tconsole.error('[simulate-bgs-battle] reference cards are empty, cannot simulate battle', cards);\r\n\t\treturn null;\r\n\t}\r\n\t// !battleInput.options?.skipInfoLogs && console.time('full-sim');\r\n\tconst start = Date.now();\r\n\tconst maxAcceptableDuration = battleInput.options?.maxAcceptableDuration || 8000;\r\n\tconst hideMaxSimulationDurationWarning = battleInput.options?.hideMaxSimulationDurationWarning ?? false;\r\n\tconst numberOfSimulations = battleInput.options?.numberOfSimulations || 8000;\r\n\tconst intermediateSteps = battleInput.options?.intermediateResults ?? 200;\r\n\tconst damageConfidence = battleInput.options?.damageConfidence ?? 0.9;\r\n\tconst includeOutcomeSamples = battleInput.options?.includeOutcomeSamples ?? true;\r\n\tconst simulationResult: SimulationResult = {\r\n\t\twonLethal: 0,\r\n\t\twon: 0,\r\n\t\ttied: 0,\r\n\t\tlost: 0,\r\n\t\tlostLethal: 0,\r\n\t\tdamageWons: [],\r\n\t\tdamageWon: 0,\r\n\t\tdamageWonRange: null,\r\n\t\tdamageLosts: [],\r\n\t\tdamageLost: 0,\r\n\t\tdamageLostRange: null,\r\n\t\twonLethalPercent: undefined,\r\n\t\twonPercent: undefined,\r\n\t\ttiedPercent: undefined,\r\n\t\tlostPercent: undefined,\r\n\t\tlostLethalPercent: undefined,\r\n\t\taverageDamageWon: undefined,\r\n\t\taverageDamageLost: undefined,\r\n\t};\r\n\r\n\tconst spectator = new Spectator(includeOutcomeSamples);\r\n\tconst inputReady = buildFinalInput(battleInput, cards, cardsData);\r\n\r\n\tapplyDebugStateFromInput(battleInput);\r\n\r\n\t// cloneInput3 normalizes the input (sorted secrets, reset pendingAttackBuffs, etc.).\r\n\t// The compiled cloner re-materializes that normalized shape as an object literal, which is\r\n\t// faster than JSON.parse of a template string (~0.02ms vs ~0.12ms per clone on a 7v7\r\n\t// board), which was itself faster than generic recursive cloners (~0.19-0.23ms) and\r\n\t// structuredClone (~0.46ms)\r\n\tconst cloneTemplate = buildTemplateCloner(cloneInput3(inputReady));\r\n\r\n\tconst runOne = () => runSingleBattle(cloneTemplate, cards, cardsData, spectator, defaultRng);\r\n\r\n\ttry {\r\n\t\t!battleInput.options?.skipInfoLogs && console.time('simulation');\r\n\t\tconst outcomes = {};\r\n\t\tfor (let i = 0; i < numberOfSimulations; i++) {\r\n\t\t\tconst battleResult = runOne();\r\n\t\t\tif (!battleResult) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (battleResult.result === 'won') {\r\n\t\t\t\tsimulationResult.won++;\r\n\t\t\t\tsimulationResult.damageWon += battleResult.damageDealt;\r\n\t\t\t\tsimulationResult.damageWons.push(battleResult.damageDealt);\r\n\t\t\t\tif (battleResult.damageDealt >= battleInput.opponentBoard.player.hpLeft) {\r\n\t\t\t\t\tsimulationResult.wonLethal++;\r\n\t\t\t\t}\r\n\t\t\t} else if (battleResult.result === 'lost') {\r\n\t\t\t\tsimulationResult.lost++;\r\n\t\t\t\tsimulationResult.damageLost += battleResult.damageDealt;\r\n\t\t\t\tsimulationResult.damageLosts.push(battleResult.damageDealt);\r\n\t\t\t\toutcomes[battleResult.damageDealt] = (outcomes[battleResult.damageDealt] ?? 0) + 1;\r\n\t\t\t\tif (\r\n\t\t\t\t\tbattleInput.playerBoard.player.hpLeft &&\r\n\t\t\t\t\tbattleResult.damageDealt >= battleInput.playerBoard.player.hpLeft\r\n\t\t\t\t) {\r\n\t\t\t\t\tsimulationResult.lostLethal++;\r\n\t\t\t\t}\r\n\t\t\t} else if (battleResult.result === 'tied') {\r\n\t\t\t\tsimulationResult.tied++;\r\n\t\t\t}\r\n\r\n\t\t\tif (Date.now() - start > maxAcceptableDuration && !hideMaxSimulationDurationWarning) {\r\n\t\t\t\t// Can happen in case of inifinite boards, or a bug. Don't hog the user's computer in that case\r\n\t\t\t\tconsole.warn('Stopping simulation after', i, 'iterations and ', Date.now() - start, 'ms');\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\t// Yield intermediate result every 200 iterations\r\n\t\t\tif (!!intermediateSteps && i > 0 && i % intermediateSteps === 0) {\r\n\t\t\t\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\r\n\t\t\t\tyield simulationResult;\r\n\t\t\t}\r\n\t\t}\r\n\t\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\r\n\t\t!battleInput.options?.skipInfoLogs && console.timeEnd('simulation');\r\n\r\n\t\t// Capture outcome samples post-hoc: re-run a few battles with action recording turned\r\n\t\t// on, until each outcome that actually occurred has a sample. This is much cheaper\r\n\t\t// than recording during the main loop, where almost all recorded actions get discarded.\r\n\t\t// This phase intentionally ignores maxAcceptableDuration: when the main loop was cut\r\n\t\t// short by the time budget, we would otherwise end up with no samples at all.\r\n\t\tif (includeOutcomeSamples) {\r\n\t\t\tconst neededOutcomes: ('won' | 'lost' | 'tied')[] = [];\r\n\t\t\tsimulationResult.won > 0 && neededOutcomes.push('won');\r\n\t\t\tsimulationResult.lost > 0 && neededOutcomes.push('lost');\r\n\t\t\tsimulationResult.tied > 0 && neededOutcomes.push('tied');\r\n\t\t\tconst missingOutcomes = new Set(neededOutcomes);\r\n\t\t\tif (missingOutcomes.size > 0) {\r\n\t\t\t\tspectator.startRecording();\r\n\t\t\t\tfor (let i = 0; i < MAX_SAMPLE_RESIMS && missingOutcomes.size > 0; i++) {\r\n\t\t\t\t\tconst battleResult = runOne();\r\n\t\t\t\t\tif (!battleResult?.result) {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tspectator.commitBattleResult(battleResult.result);\r\n\t\t\t\t\tif (spectator.hasSampleFor(battleResult.result)) {\r\n\t\t\t\t\t\tmissingOutcomes.delete(battleResult.result);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tspectator.stopRecording();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tspectator.prune();\r\n\t\tsimulationResult.outcomeSamples = spectator.buildOutcomeSamples(battleInput.gameState);\r\n\t\t// Avoid sending this verbose data\r\n\r\n\t\tsimulationResult.damageWons = [];\r\n\t\tsimulationResult.damageLosts = [];\r\n\t\t// !battleInput.options?.skipInfoLogs && console.timeEnd('full-sim');\r\n\t\treturn simulationResult;\r\n\t} finally {\r\n\t\tclearDebugStateFromInput(battleInput);\r\n\t}\r\n};\r\n\r\ntype CloneTemplate = () => BgsBattleInfo;\r\n\r\nconst runSingleBattle = (\r\n\tcloneTemplate: CloneTemplate,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n\tspectator: Spectator,\r\n\trng: Rng,\r\n): SingleSimulationResult => {\r\n\tconst input: BgsBattleInfo = cloneTemplate();\r\n\t// The \"initial\" states are only read by a handful of cards (and mutated by some, like\r\n\t// San'layn Scribe), so we only pay for the second clone when they are actually accessed\r\n\tlet playerInitialState = null;\r\n\tlet opponentInitialState = null;\r\n\tconst buildInitialStates = () => {\r\n\t\tconst inputClone: BgsBattleInfo = cloneTemplate();\r\n\t\tplayerInitialState = {\r\n\t\t\tplayer: inputClone.playerBoard.player,\r\n\t\t\tboard: inputClone.playerBoard.board,\r\n\t\t\tteammate: inputClone.playerTeammateBoard,\r\n\t\t};\r\n\t\topponentInitialState = {\r\n\t\t\tplayer: inputClone.opponentBoard.player,\r\n\t\t\tboard: inputClone.opponentBoard.board,\r\n\t\t\tteammate: inputClone.opponentTeammateBoard,\r\n\t\t};\r\n\t};\r\n\tconst gameState: FullGameState = {\r\n\t\tallCards: cards,\r\n\t\tcardsData: cardsData,\r\n\t\tspectator: spectator,\r\n\t\tsharedState: new SharedState(rng),\r\n\t\tcurrentTurn: input.gameState.currentTurn,\r\n\t\tnumberOfPlayersAlive: input.gameState.numberOfPlayersAlive,\r\n\t\tapplyDamageCap: input.options?.applyDamageCap === true,\r\n\t\tapplyIceBlock: input.options?.applyIceBlock === true,\r\n\t\tisDuos: !!input.playerTeammateBoard || !!input.opponentTeammateBoard,\r\n\t\tvalidTribes: input.gameState.validTribes,\r\n\t\tanomalies: input.gameState.anomalies,\r\n\t\tgameState: {\r\n\t\t\tplayer: {\r\n\t\t\t\tplayer: input.playerBoard.player,\r\n\t\t\t\tboard: input.playerBoard.board,\r\n\t\t\t\tteammate: input.playerTeammateBoard,\r\n\t\t\t},\r\n\t\t\topponent: {\r\n\t\t\t\tplayer: input.opponentBoard.player,\r\n\t\t\t\tboard: input.opponentBoard.board,\r\n\t\t\t\tteammate: input.opponentTeammateBoard,\r\n\t\t\t},\r\n\t\t\tget playerInitial() {\r\n\t\t\t\tif (!playerInitialState) {\r\n\t\t\t\t\tbuildInitialStates();\r\n\t\t\t\t}\r\n\t\t\t\treturn playerInitialState;\r\n\t\t\t},\r\n\t\t\tget opponentInitial() {\r\n\t\t\t\tif (!opponentInitialState) {\r\n\t\t\t\t\tbuildInitialStates();\r\n\t\t\t\t}\r\n\t\t\t\treturn opponentInitialState;\r\n\t\t\t},\r\n\t\t},\r\n\t};\r\n\tconst simulator = new Simulator(gameState);\r\n\treturn simulator.simulateSingleBattle(gameState.gameState.player, gameState.gameState.opponent);\r\n};\r\n\r\nconst applyDebugStateFromInput = (battleInput: BgsBattleInfo) => {\r\n\tif (!battleInput.debugState) {\r\n\t\treturn;\r\n\t}\r\n\tdebugState.active = true;\r\n\tdebugState.forcedCurrentAttacker = battleInput.debugState.forcedCurrentAttacker;\r\n\tdebugState.forcedFaceOffBase =\r\n\t\tbattleInput.debugState.forcedFaceOffBase?.map((f) => ({\r\n\t\t\tattacker: { ...f.attacker },\r\n\t\t\tdefender: { ...f.defender },\r\n\t\t})) ?? [];\r\n\tconst rawPicks = battleInput.debugState.forcedRandomPicks ?? [];\r\n\tdebugState.forcedRandomPicksBase = rawPicks.map((p) => ({\r\n\t\tsource: { ...p.source },\r\n\t\ttarget: { ...p.target },\r\n\t\t...(p.chosenCardId && { chosenCardId: p.chosenCardId }),\r\n\t}));\r\n};\r\n\r\nconst clearDebugStateFromInput = (battleInput: BgsBattleInfo) => {\r\n\tif (battleInput.debugState) {\r\n\t\tdebugState.active = false;\r\n\t}\r\n};\r\n\r\nconst updateSimulationResult = (simulationResult: SimulationResult, input: BgsBattleInfo, damageConfidence: number) => {\r\n\tconst totalMatches = simulationResult.won + simulationResult.tied + simulationResult.lost;\r\n\tsimulationResult.wonPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.won)) / totalMatches) / 10,\r\n\t\tsimulationResult.won,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.wonLethalPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10,\r\n\t\tsimulationResult.wonLethal,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.lostPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.lost)) / totalMatches) / 10,\r\n\t\tsimulationResult.lost,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.lostLethalPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10,\r\n\t\tsimulationResult.lostLethal,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.tiedPercent = checkRounding(\r\n\t\tMath.max(0, 100 - simulationResult.lostPercent - simulationResult.wonPercent),\r\n\t\tsimulationResult.tied,\r\n\t\ttotalMatches,\r\n\t);\r\n\r\n\t// simulationResult.wonLethalPercent = Math.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10;\r\n\t// simulationResult.lostLethalPercent = Math.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10;\r\n\tconst totalDamageWon = simulationResult.damageWons.reduce((a, b) => a + b, 0);\r\n\tconst totalDamageLost = simulationResult.damageLosts.reduce((a, b) => a + b, 0);\r\n\tconst damageWonRange = calculateDamageRange(simulationResult.damageWons, damageConfidence);\r\n\tconst damageLostRange = calculateDamageRange(simulationResult.damageLosts, damageConfidence);\r\n\tsimulationResult.averageDamageWon = simulationResult.won ? totalDamageWon / simulationResult.won : 0;\r\n\tsimulationResult.averageDamageLost = simulationResult.lost ? totalDamageLost / simulationResult.lost : 0;\r\n\tsimulationResult.damageWonRange = simulationResult.won ? damageWonRange : null;\r\n\tsimulationResult.damageLostRange = simulationResult.lost ? damageLostRange : null;\r\n\r\n\tif (\r\n\t\tsimulationResult.averageDamageWon > 0 &&\r\n\t\tsimulationResult.averageDamageWon < input.playerBoard.player.tavernTier\r\n\t) {\r\n\t\tconsole.warn('average damage won issue');\r\n\t}\r\n\tif (\r\n\t\tsimulationResult.averageDamageLost > 0 &&\r\n\t\tsimulationResult.averageDamageLost < input.opponentBoard.player.tavernTier\r\n\t) {\r\n\t\tconsole.warn('average damage lost issue');\r\n\t}\r\n};\r\n\r\nconst calculateDamageRange = (damageArray: number[], damageConfidence: number): { min: number; max: number } => {\r\n\tif (damageArray.length === 0) {\r\n\t\treturn { min: 0, max: 0 };\r\n\t}\r\n\r\n\t// Sort the array\r\n\tconst sortedDamage = [...damageArray].sort((a, b) => a - b);\r\n\r\n\t// Calculate the 10th and 90th percentiles\r\n\tconst percentile = (arr: number[], p: number) => {\r\n\t\tconst index = Math.floor(p * arr.length);\r\n\t\treturn arr[index];\r\n\t};\r\n\r\n\tconst minDamage = percentile(sortedDamage, 1 - damageConfidence);\r\n\tconst maxDamage = percentile(sortedDamage, damageConfidence);\r\n\r\n\treturn { min: minDamage, max: maxDamage };\r\n};\r\n\r\nconst checkRounding = (roundedValue: number, initialValue: number, totalValue: number): number => {\r\n\tif (roundedValue === 0 && initialValue !== 0) {\r\n\t\treturn 0.01;\r\n\t}\r\n\tif (roundedValue === 100 && initialValue !== totalValue) {\r\n\t\treturn 99.9;\r\n\t}\r\n\treturn roundedValue;\r\n};\r\n\r\n// const cleanEnchantmentsForEntity = (\r\n// \tenchantments: { cardId: string; originEntityId?: number; timing: number }[],\r\n// \tentityIds: readonly number[],\r\n// ): { cardId: string; originEntityId?: number; timing: number }[] => {\r\n// \treturn enchantments.filter(\r\n// \t\t(enchant) =>\r\n// \t\t\tentityIds.indexOf(enchant.originEntityId) !== -1 ||\r\n// \t\t\tvalidEnchantments.indexOf(enchant.cardId as CardIds) !== -1,\r\n// \t);\r\n// };\r\n"]}
|
|
@@ -14,8 +14,8 @@ const onDeathrattleTriggered = (input) => {
|
|
|
14
14
|
}
|
|
15
15
|
for (const enchantment of (_a = boardEntity.enchantments) !== null && _a !== void 0 ? _a : []) {
|
|
16
16
|
const onDeathrattleTriggered = _card_mappings_1.cardMappings[enchantment.cardId];
|
|
17
|
-
if ((0, card_interface_1.
|
|
18
|
-
onDeathrattleTriggered.
|
|
17
|
+
if ((0, card_interface_1.hasOnDeathrattleTriggeredEnchantment)(onDeathrattleTriggered)) {
|
|
18
|
+
onDeathrattleTriggered.onDeathrattleTriggeredEnchantment(boardEntity, enchantment, input);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deathrattle-on-trigger.js","sourceRoot":"","sources":["../../src/simulation/deathrattle-on-trigger.ts"],"names":[],"mappings":";;;AAAA,iEAAuD;AAGvD,
|
|
1
|
+
{"version":3,"file":"deathrattle-on-trigger.js","sourceRoot":"","sources":["../../src/simulation/deathrattle-on-trigger.ts"],"names":[],"mappings":";;;AAAA,iEAAuD;AAGvD,4DAA0G;AAC1G,iEAA4D;AAG5D,mCAAiD;AAY1C,MAAM,sBAAsB,GAAG,CAAC,KAAgC,EAAE,EAAE;;IAC1E,KAAK,MAAM,WAAW,IAAI,KAAK,CAAC,mBAAmB,EAAE;QACpD,MAAM,sBAAsB,GAAG,6BAAY,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAChE,IAAI,IAAA,0CAAyB,EAAC,sBAAsB,CAAC,EAAE;YACtD,sBAAsB,CAAC,sBAAsB,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;SAClE;QACD,KAAK,MAAM,WAAW,IAAI,MAAA,WAAW,CAAC,YAAY,mCAAI,EAAE,EAAE;YACzD,MAAM,sBAAsB,GAAG,6BAAY,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAChE,IAAI,IAAA,qDAAoC,EAAC,sBAAsB,CAAC,EAAE;gBACjE,sBAAsB,CAAC,iCAAiC,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;aAC1F;SACD;KACD;IACD,KAAK,MAAM,OAAO,IAAI,MAAA,KAAK,CAAC,uBAAuB,CAAC,QAAQ,mCAAI,EAAE,EAAE;QACnE,MAAM,sBAAsB,GAAG,6BAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC5D,IAAI,IAAA,0CAAyB,EAAC,sBAAsB,CAAC,EAAE;YACtD,sBAAsB,CAAC,sBAAsB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;SAC9D;KACD;IAED,MAAM,MAAM,GAAG,MAAA,KAAK,CAAC,uBAAuB,CAAC,aAAa,mCAAI,EAAE,CAAC;IACjE,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;QAC3B,QAAQ,KAAK,CAAC,MAAM,EAAE;YACrB;gBACC,IAAA,8BAAsB,EACrB,KAAK,CAAC,uBAAuB,EAC7B,KAAK,EACL,KAAK,CAAC,mBAAmB,EACzB,KAAK,CAAC,SAAS,CACf,CAAC;gBACF,MAAM;SACP;KACD;IAED,KAAK,CAAC,uBAAuB,CAAC,QAAQ;SACpC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,yBAAiD,CAAC;SACxE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QACd,CAAC,CAAC,IAAI,CAAC,wBAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAvCW,QAAA,sBAAsB,0BAuCjC","sourcesContent":["import { GameTag } from '@firestone-hs/reference-data';\r\nimport { BgsPlayerEntity } from '../bgs-player-entity';\r\nimport { BoardEntity } from '../board-entity';\r\nimport { hasOnDeathrattleTriggered, hasOnDeathrattleTriggeredEnchantment } from '../cards/card.interface';\r\nimport { cardMappings } from '../cards/impl/_card-mappings';\r\nimport { CardIds } from '../services/card-ids';\r\nimport { FullGameState } from './internal-game-state';\r\nimport { onQuestProgressUpdated } from './quest';\r\n\r\nexport interface DeathrattleTriggeredInput {\r\n\treadonly boardWithDeadEntity: BoardEntity[];\r\n\treadonly boardWithDeadEntityHero: BgsPlayerEntity;\r\n\treadonly deadEntity: BoardEntity;\r\n\treadonly otherBoard: BoardEntity[];\r\n\treadonly otherBoardHero: BgsPlayerEntity;\r\n\treadonly deadEntityIndexFromRight?: number;\r\n\treadonly gameState: FullGameState;\r\n}\r\n\r\nexport const onDeathrattleTriggered = (input: DeathrattleTriggeredInput) => {\r\n\tfor (const boardEntity of input.boardWithDeadEntity) {\r\n\t\tconst onDeathrattleTriggered = cardMappings[boardEntity.cardId];\r\n\t\tif (hasOnDeathrattleTriggered(onDeathrattleTriggered)) {\r\n\t\t\tonDeathrattleTriggered.onDeathrattleTriggered(boardEntity, input);\r\n\t\t}\r\n\t\tfor (const enchantment of boardEntity.enchantments ?? []) {\r\n\t\t\tconst onDeathrattleTriggered = cardMappings[enchantment.cardId];\r\n\t\t\tif (hasOnDeathrattleTriggeredEnchantment(onDeathrattleTriggered)) {\r\n\t\t\t\tonDeathrattleTriggered.onDeathrattleTriggeredEnchantment(boardEntity, enchantment, input);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tfor (const trinket of input.boardWithDeadEntityHero.trinkets ?? []) {\r\n\t\tconst onDeathrattleTriggered = cardMappings[trinket.cardId];\r\n\t\tif (hasOnDeathrattleTriggered(onDeathrattleTriggered)) {\r\n\t\t\tonDeathrattleTriggered.onDeathrattleTriggered(trinket, input);\r\n\t\t}\r\n\t}\r\n\r\n\tconst quests = input.boardWithDeadEntityHero.questEntities ?? [];\r\n\tfor (const quest of quests) {\r\n\t\tswitch (quest.CardId) {\r\n\t\t\tcase CardIds.ExhumeTheBones:\r\n\t\t\t\tonQuestProgressUpdated(\r\n\t\t\t\t\tinput.boardWithDeadEntityHero,\r\n\t\t\t\t\tquest,\r\n\t\t\t\t\tinput.boardWithDeadEntity,\r\n\t\t\t\t\tinput.gameState,\r\n\t\t\t\t);\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\r\n\tinput.boardWithDeadEntityHero.trinkets\r\n\t\t.filter((t) => t.cardId === CardIds.DeathlyPhylactery_BG30_MagicItem_700)\r\n\t\t.forEach((t) => {\r\n\t\t\tt.tags[GameTag.TRIGGER_VISUAL] = 0;\r\n\t\t});\r\n};\r\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"soc-illidan-hero-power.js","sourceRoot":"","sources":["../../../src/simulation/start-of-combat/soc-illidan-hero-power.ts"],"names":[],"mappings":"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","sourcesContent":["import { BgsPlayerEntity } from '../../bgs-player-entity';\r\nimport { BoardEntity } from '../../board-entity';\r\nimport { CardIds } from '../../services/card-ids';\r\nimport { processMinionDeath, simulateAttack } from '../attack';\r\nimport { FullGameState } from '../internal-game-state';\r\nimport { modifyStats } from '../stats';\r\nimport { handleSummonsWhenSpace } from '../summon-when-space';\r\n\r\nexport const handleIllidanHeroPowers = (\r\n\tplayerEntity: BgsPlayerEntity,\r\n\tplayerBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\tcurrentAttacker: number,\r\n\tgameState: FullGameState,\r\n): { attacker: number; force: boolean } => {\r\n\tlet shouldForce = false;\r\n\t// console.log('current attacker before', currentAttacker);\r\n\t// Apparently it's a toin coss about whether to handle Illidan first or Al'Akir first\r\n\t// Auras are only relevant for Illidan, and already applied there\r\n\tif (Math.random() < 0.5) {\r\n\t\tconst { attacker: newAttacker, force: force1 } = handlePlayerIllidanHeroPowers(\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerBoard,\r\n\t\t\topponentEntity,\r\n\t\t\topponentBoard,\r\n\t\t\tcurrentAttacker,\r\n\t\t\ttrue,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tconst { attacker: newAttacker2, force: force2 } = handlePlayerIllidanHeroPowers(\r\n\t\t\topponentEntity,\r\n\t\t\topponentBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerBoard,\r\n\t\t\tnewAttacker,\r\n\t\t\tfalse,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tshouldForce = force1 || force2;\r\n\t\tcurrentAttacker = newAttacker2;\r\n\t} else {\r\n\t\tconst { attacker: newAttacker, force: force1 } = handlePlayerIllidanHeroPowers(\r\n\t\t\topponentEntity,\r\n\t\t\topponentBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerBoard,\r\n\t\t\tcurrentAttacker,\r\n\t\t\tfalse,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tconst { attacker: newAttacker2, force: force2 } = handlePlayerIllidanHeroPowers(\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerBoard,\r\n\t\t\topponentEntity,\r\n\t\t\topponentBoard,\r\n\t\t\tnewAttacker,\r\n\t\t\ttrue,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tshouldForce = force1 || force2;\r\n\t\tcurrentAttacker = newAttacker2;\r\n\t}\r\n\tprocessMinionDeath(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState);\r\n\tconst shouldRecomputeCurrentAttacker = handleSummonsWhenSpace(\r\n\t\tplayerBoard,\r\n\t\tplayerEntity,\r\n\t\topponentBoard,\r\n\t\topponentEntity,\r\n\t\tgameState,\r\n\t);\r\n\tif (shouldForce) {\r\n\t\treturn { attacker: currentAttacker, force: true };\r\n\t}\r\n\tif (shouldRecomputeCurrentAttacker) {\r\n\t\tcurrentAttacker =\r\n\t\t\tplayerBoard.length > opponentBoard.length\r\n\t\t\t\t? 0\r\n\t\t\t\t: opponentBoard.length > playerBoard.length\r\n\t\t\t\t? 1\r\n\t\t\t\t: Math.round(Math.random());\r\n\t}\r\n\treturn { attacker: currentAttacker, force: false };\r\n};\r\n\r\nconst handlePlayerIllidanHeroPowers = (\r\n\tplayerEntity: BgsPlayerEntity,\r\n\tplayerBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\tcurrentAttacker: number,\r\n\tfriendly: boolean,\r\n\tgameState: FullGameState,\r\n): { attacker: number; force: boolean } => {\r\n\tconst loops = playerEntity.trinkets?.some((t) => t.cardId === CardIds.ValdrakkenWindChimes_BG32_MagicItem_365)\r\n\t\t? 2\r\n\t\t: 1;\r\n\tfor (let i = 0; i < loops; i++) {\r\n\t\tif (playerEntity.hpLeft <= 0) {\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t\t}\r\n\t\tfor (const heroPower of playerEntity.heroPowers) {\r\n\t\t\tif (heroPower.cardId === CardIds.Wingmen && playerBoard.length > 0) {\r\n\t\t\t\t// After Illidan triggers, it's always the other opponent's turn\r\n\t\t\t\t// https://x.com/LoewenMitchell/status/1752714583360639131?s=20\r\n\t\t\t\t// Confirmed by BoarControl on Discord on 33.6.2 2025-10-20\r\n\t\t\t\thandleIllidanForPlayer(\r\n\t\t\t\t\tplayerBoard,\r\n\t\t\t\t\tplayerEntity,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentEntity,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t\tcurrentAttacker,\r\n\t\t\t\t);\r\n\t\t\t\tcurrentAttacker = friendly ? 1 : 0;\r\n\t\t\t\t// This is not true anymore: https://replays.firestoneapp.com/?reviewId=7282387d-66cd-458e-8ee1-e04c662e7bad&turn=5&action=1\r\n\t\t\t\t// In fact there is some adjustment going on: https://replays.firestoneapp.com/?reviewId=929f676f-47f6-494b-9619-df04174a0150&turn=11&action=0\r\n\t\t\t\t// So trying another logic\r\n\t\t\t\t// currentAttacker = (currentAttacker + 1) % 2;\r\n\t\t\t\t// This isn't correct. The following game is a case of:\r\n\t\t\t\t// The player with the fewer minions is Illidan, so isn't the \"first attacker\"\r\n\t\t\t\t// Wingmen triggers\r\n\t\t\t\t// The non-Illidan side then attacks first\r\n\t\t\t\t// https://replays.firestoneapp.com/?reviewId=45f40e73-4be9-419f-9093-0c2d91a7bac2&turn=5&action=0\r\n\t\t\t\t// So for now, just randomizing the attacker to try and avoid \"impossible\" scenarios as much as possible\r\n\t\t\t\t// currentAttacker = Math.random() < 0.5 ? 0 : 1;\r\n\r\n\t\t\t\t// It looks like it's always the next player that should attack after Wingmen triggers, which\r\n\t\t\t\t// means we should bypass the \"recompute next attacker\" logic from other start of combat effects,\r\n\t\t\t\t// like summoning Flight Scout\r\n\t\t\t\t// 33.6.2 https://replays.firestoneapp.com/?reviewId=03b5755e-1666-4f6c-a3be-626b76bbef6d&turn=5&action=1\r\n\t\t\t\t// 33.6.2 https://replays.firestoneapp.com/?reviewId=c04ab462-9fd2-47e4-8ad4-bbcc3c14c709&turn=3&action=2\r\n\t\t\t\treturn { attacker: currentAttacker, force: true };\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn { attacker: currentAttacker, force: false };\r\n};\r\n\r\n// TODO: not exactly correct, because of \"attack immediately\", but it's close enough\r\nconst handleIllidanForPlayer = (\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n\tcurrentAttacker: number,\r\n): void => {\r\n\tif (playerEntity.startOfCombatDone) {\r\n\t\treturn;\r\n\t}\r\n\t// Otherwise, if the first minion dies on the attack, and the board has only 2 minions, we\r\n\t// miss the second one\r\n\tconst minionsAtStart = playerBoard.length;\r\n\tconst firstAttacker = playerBoard[0];\r\n\tconst secondAttacker = minionsAtStart > 1 ? playerBoard[playerBoard.length - 1] : null;\r\n\r\n\t// Stats updates\r\n\tmodifyStats(firstAttacker, playerEntity, 2, 1, playerBoard, playerEntity, gameState);\r\n\tif (!!secondAttacker && !secondAttacker.definitelyDead && secondAttacker.health > 0) {\r\n\t\tmodifyStats(secondAttacker, playerEntity, 2, 1, playerBoard, playerEntity, gameState);\r\n\t}\r\n\r\n\t// Attacks\r\n\tfirstAttacker.attackImmediately = true;\r\n\tsimulateAttack(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState, {\r\n\t\tskipSummonWhenSpace: true,\r\n\t});\r\n\t// See http://replays.firestoneapp.com/?reviewId=f16b7a49-c2a2-4ac5-a9eb-a75f83246f70&turn=6&action=8\r\n\tfirstAttacker.hasAttacked = undefined;\r\n\tfirstAttacker.attackImmediately = false;\r\n\tif (!!secondAttacker && !secondAttacker.definitelyDead && secondAttacker.health > 0) {\r\n\t\tsecondAttacker.attackImmediately = true;\r\n\t\tsimulateAttack(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState, {\r\n\t\t\tskipSummonWhenSpace: true,\r\n\t\t});\r\n\t\tsecondAttacker.hasAttacked = undefined;\r\n\t\tsecondAttacker.attackImmediately = false;\r\n\t}\r\n\r\n\t// // See http://replays.firestoneapp.com/?reviewId=7e9ec42c-a8f6-43d2-9f39-cc486dfa2395&turn=6&action=5\r\n\t// if (firstAttacker.definitelyDead || firstAttacker.health <= 0) {\r\n\t// \tcurrentAttacker = (currentAttacker + 1) % 2;\r\n\t// }\r\n\t// return currentAttacker;\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"file":"soc-illidan-hero-power.js","sourceRoot":"","sources":["../../../src/simulation/start-of-combat/soc-illidan-hero-power.ts"],"names":[],"mappings":"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","sourcesContent":["import { BgsPlayerEntity } from '../../bgs-player-entity';\r\nimport { BoardEntity } from '../../board-entity';\r\nimport { CardIds } from '../../services/card-ids';\r\nimport { processMinionDeath, simulateAttack } from '../attack';\r\nimport { FullGameState } from '../internal-game-state';\r\nimport { modifyStats } from '../stats';\r\nimport { handleSummonsWhenSpace } from '../summon-when-space';\r\n\r\nexport const handleIllidanHeroPowers = (\r\n\tplayerEntity: BgsPlayerEntity,\r\n\tplayerBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\tcurrentAttacker: number,\r\n\tgameState: FullGameState,\r\n): { attacker: number; force: boolean } => {\r\n\tlet shouldForce = false;\r\n\t// console.log('current attacker before', currentAttacker);\r\n\t// Apparently it's a toin coss about whether to handle Illidan first or Al'Akir first\r\n\t// Auras are only relevant for Illidan, and already applied there\r\n\tif (Math.random() < 0.5) {\r\n\t\tconst { attacker: newAttacker, force: force1 } = handlePlayerIllidanHeroPowers(\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerBoard,\r\n\t\t\topponentEntity,\r\n\t\t\topponentBoard,\r\n\t\t\tcurrentAttacker,\r\n\t\t\ttrue,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tconst { attacker: newAttacker2, force: force2 } = handlePlayerIllidanHeroPowers(\r\n\t\t\topponentEntity,\r\n\t\t\topponentBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerBoard,\r\n\t\t\tnewAttacker,\r\n\t\t\tfalse,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tshouldForce = force1 || force2;\r\n\t\tcurrentAttacker = newAttacker2;\r\n\t} else {\r\n\t\tconst { attacker: newAttacker, force: force1 } = handlePlayerIllidanHeroPowers(\r\n\t\t\topponentEntity,\r\n\t\t\topponentBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerBoard,\r\n\t\t\tcurrentAttacker,\r\n\t\t\tfalse,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tconst { attacker: newAttacker2, force: force2 } = handlePlayerIllidanHeroPowers(\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerBoard,\r\n\t\t\topponentEntity,\r\n\t\t\topponentBoard,\r\n\t\t\tnewAttacker,\r\n\t\t\ttrue,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tshouldForce = force1 || force2;\r\n\t\tcurrentAttacker = newAttacker2;\r\n\t}\r\n\tprocessMinionDeath(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState);\r\n\tconst shouldRecomputeCurrentAttacker = handleSummonsWhenSpace(\r\n\t\tplayerBoard,\r\n\t\tplayerEntity,\r\n\t\topponentBoard,\r\n\t\topponentEntity,\r\n\t\tgameState,\r\n\t);\r\n\tif (shouldForce) {\r\n\t\treturn { attacker: currentAttacker, force: true };\r\n\t}\r\n\tif (shouldRecomputeCurrentAttacker) {\r\n\t\tcurrentAttacker =\r\n\t\t\tplayerBoard.length > opponentBoard.length\r\n\t\t\t\t? 0\r\n\t\t\t\t: opponentBoard.length > playerBoard.length\r\n\t\t\t\t? 1\r\n\t\t\t\t: Math.round(Math.random());\r\n\t}\r\n\treturn { attacker: currentAttacker, force: false };\r\n};\r\n\r\nconst handlePlayerIllidanHeroPowers = (\r\n\tplayerEntity: BgsPlayerEntity,\r\n\tplayerBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\tcurrentAttacker: number,\r\n\tfriendly: boolean,\r\n\tgameState: FullGameState,\r\n): { attacker: number; force: boolean } => {\r\n\tconst loops = playerEntity.trinkets?.some((t) => t.cardId === CardIds.ValdrakkenWindChimes_BG32_MagicItem_365)\r\n\t\t? 2\r\n\t\t: 1;\r\n\tfor (let i = 0; i < loops; i++) {\r\n\t\tif (playerEntity.hpLeft <= 0) {\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t\t}\r\n\t\tfor (const heroPower of playerEntity.heroPowers) {\r\n\t\t\tif (heroPower.cardId === CardIds.Wingmen && playerBoard.length > 0) {\r\n\t\t\t\thandleIllidanForPlayer(\r\n\t\t\t\t\tplayerBoard,\r\n\t\t\t\t\tplayerEntity,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentEntity,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t\tcurrentAttacker,\r\n\t\t\t\t);\r\n\t\t\t\t// After Illidan triggers, it's always the other opponent's turn\r\n\t\t\t\t// https://x.com/LoewenMitchell/status/1752714583360639131?s=20\r\n\t\t\t\t// Confirmed by BoarControl on Discord on 33.6.2 2025-10-20\r\n\t\t\t\t// It looks like it's always the next player that should attack after Wingmen triggers, which\r\n\t\t\t\t// means we should bypass the \"recompute next attacker\" logic from other start of combat effects,\r\n\t\t\t\t// like summoning Flight Scout\r\n\t\t\t\t// 33.6.2 https://replays.firestoneapp.com/?reviewId=03b5755e-1666-4f6c-a3be-626b76bbef6d&turn=5&action=1\r\n\t\t\t\t// 33.6.2 https://replays.firestoneapp.com/?reviewId=c04ab462-9fd2-47e4-8ad4-bbcc3c14c709&turn=3&action=2\r\n\t\t\t\tcurrentAttacker = friendly ? 1 : 0;\r\n\t\t\t\t// UPDATE 2026-09-04: looks like it's not always the case, but I haven't been able to figure out the rules\r\n\t\t\t\t// 36.4.2: https://replays.firestoneapp.com/?reviewId=a2a8a059-a8de-4c42-a467-2693f222c691&turn=11&action=2\r\n\t\t\t\treturn { attacker: currentAttacker, force: true };\r\n\t\t\t\t// OLD:\r\n\t\t\t\t// This is not true anymore: https://replays.firestoneapp.com/?reviewId=7282387d-66cd-458e-8ee1-e04c662e7bad&turn=5&action=1\r\n\t\t\t\t// In fact there is some adjustment going on: https://replays.firestoneapp.com/?reviewId=929f676f-47f6-494b-9619-df04174a0150&turn=11&action=0\r\n\t\t\t\t// So trying another logic\r\n\t\t\t\t// currentAttacker = (currentAttacker + 1) % 2;\r\n\t\t\t\t// This isn't correct. The following game is a case of:\r\n\t\t\t\t// The player with the fewer minions is Illidan, so isn't the \"first attacker\"\r\n\t\t\t\t// Wingmen triggers\r\n\t\t\t\t// The non-Illidan side then attacks first\r\n\t\t\t\t// https://replays.firestoneapp.com/?reviewId=45f40e73-4be9-419f-9093-0c2d91a7bac2&turn=5&action=0\r\n\t\t\t\t// So for now, just randomizing the attacker to try and avoid \"impossible\" scenarios as much as possible\r\n\t\t\t\t// currentAttacker = Math.random() < 0.5 ? 0 : 1;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn { attacker: currentAttacker, force: false };\r\n};\r\n\r\n// TODO: not exactly correct, because of \"attack immediately\", but it's close enough\r\nconst handleIllidanForPlayer = (\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n\tcurrentAttacker: number,\r\n): void => {\r\n\tif (playerEntity.startOfCombatDone) {\r\n\t\treturn;\r\n\t}\r\n\t// Otherwise, if the first minion dies on the attack, and the board has only 2 minions, we\r\n\t// miss the second one\r\n\tconst minionsAtStart = playerBoard.length;\r\n\tconst firstAttacker = playerBoard[0];\r\n\tconst secondAttacker = minionsAtStart > 1 ? playerBoard[playerBoard.length - 1] : null;\r\n\r\n\t// Stats updates\r\n\tmodifyStats(firstAttacker, playerEntity, 2, 1, playerBoard, playerEntity, gameState);\r\n\tif (!!secondAttacker && !secondAttacker.definitelyDead && secondAttacker.health > 0) {\r\n\t\tmodifyStats(secondAttacker, playerEntity, 2, 1, playerBoard, playerEntity, gameState);\r\n\t}\r\n\r\n\t// Attacks\r\n\tfirstAttacker.attackImmediately = true;\r\n\tsimulateAttack(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState, {\r\n\t\tskipSummonWhenSpace: true,\r\n\t});\r\n\t// See http://replays.firestoneapp.com/?reviewId=f16b7a49-c2a2-4ac5-a9eb-a75f83246f70&turn=6&action=8\r\n\tfirstAttacker.hasAttacked = undefined;\r\n\tfirstAttacker.attackImmediately = false;\r\n\tif (!!secondAttacker && !secondAttacker.definitelyDead && secondAttacker.health > 0) {\r\n\t\tsecondAttacker.attackImmediately = true;\r\n\t\tsimulateAttack(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState, {\r\n\t\t\tskipSummonWhenSpace: true,\r\n\t\t});\r\n\t\tsecondAttacker.hasAttacked = undefined;\r\n\t\tsecondAttacker.attackImmediately = false;\r\n\t}\r\n\r\n\t// // See http://replays.firestoneapp.com/?reviewId=7e9ec42c-a8f6-43d2-9f39-cc486dfa2395&turn=6&action=5\r\n\t// if (firstAttacker.definitelyDead || firstAttacker.health <= 0) {\r\n\t// \tcurrentAttacker = (currentAttacker + 1) % 2;\r\n\t// }\r\n\t// return currentAttacker;\r\n};\r\n"]}
|