Rewrite enchantments #400
No reviewers
Labels
No labels
breaking change
duplicate
good first issue
help wanted
invalid
question
scope: card
scope: docs
scope: game
scope: registry
scope: script
scope: tool
scope: universe
tracker
type: bug
type: card request
type: documentation
type: enhancement
type: improvement
type: parity
wontfix
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
LunarTides/Hearthstone.js!400
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "rewrite-enchantments"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #275
Turned out to be harder than I thought, but not quite impossible!
enchantmentSetupin place ofsetup.The
Card.activeEnchantmentsarray currently uses actual cards instead of Blueprints. This isn't great memory-wise, but it will allow enchantments to change over time. If, for example, an enchantment has some weird effect like "+1 Attack. If the card has had this enchantment for over 3 turns, +2 Attack" or something like that, it would be helpful to be able to use theselfparameter. Cuz that's the thing. If it's a blueprint, then theselfparameter would be unavailable, and therefore you couldn't useself.turnto see if the enchantment has been active for more than 3 turns. Although in this example, the enchantment could do some hack by putting the game's turn inhost.storageif it doesn't already exist and using that, something like this:But if it was an actual card, it would be a lot easier:
And I'm sure that some things are just straight up impossible without the enchantment being an actual card, so whatever. The game can handle a little more memory usage... probably...
Unless you add like a million enchantments to one card, but I feel like there's other bottlenecks, like
game.activeCards, so it's fine...Summary by CodeRabbit
New Features
Improvements
Walkthrough
Replaces string-based enchantments with card-based Enchantment type, adds ID-based async add/remove APIs, introduces enchantment priority and lifecycle hooks, updates types, core card logic, examples, tests, tooling, and card registry entries.
Changes
src/types/card.tsLocation,EnchantmentPriority,EnchantmentDefinition,CardBackup; extendedTypeandAbilityfor Enchantment callbacks; updated Blueprint abilities and signatures to include enchantment callbacks and priority.src/card.tsactiveEnchantmentsandenchantmentPriority; added asyncaddEnchantment(enchantmentId, owner),removeEnchantment(enchantmentId, card),enchantmentExists, andrefreshEnchantments(); refactored trigger to delegate to_trigger.src/game.ts,src/event.tsEnchantmentplay handler inplayCard.typeSpecific;HandTicknow awaitscard.refreshEnchantments()instead of calling sync apply method.src/functions/card.ts,src/functions/util.tsAbility.EnchantmentApply/EnchantmentRemovefor Enchantment type;getRandomTargetgains optional filter predicate andgetRandomTargetRelativehelper.cards/ids.ts,cards/.latestIdenchantmentExample_56→enchantmentApplyExample_56; added IDs 142–147; bumped.latestId141 → 147.cards/Classes/Neutral/Uncollectible/Enchantments/.../144-fates-blessing.ts,cards/Galakrond/Rogue/145-galakronds-blessing.tsenchantmentSetup,enchantmentApply,enchantmentRemoveto enforce 0-cost and restore previous cost.cards/Examples/4/*,cards/Examples/Test/*cards/.../104-yogg-saron-master-of-fate.ts,cards/Galakrond/Rogue/67-hero.tsgame.cardIds.*constants.tools/cardcreator/lib.ts,tools/cardcreator/custom.ts,tools/cardcreator/vanilla.tsenchantmentPriorityhandling, updated generated code to emit enchantment-specific callbacks and imports.scripts/test/crash.tsSequence Diagram(s)
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~50 minutes
Poem
Pre-merge checks and finishing touches
✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
rewrite-enchantmentsThanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
❤️ Share
Comment
@coderabbitai helpto get the list of available commands and usage tips.Issue / PR #400 btw!
Some changes required :)
Add this to the
EnchantmentPrioritytype.Do:
Oops! Use
sortinstead oftoSortedyou dummy!@ -1,5 +1,6 @@import { Card } from "@Game/card.ts";Remove
@ -540,7 +542,30 @@ ${mainContent}targets.push(...game.player2.board);}Maybe do
includeOpposingPlayerandincludeOpposingBoardinstead.@ -244,6 +246,26 @@ const cardTypeFunctions: {return applyCard(card);I'm not sure if this would work if I were to change the values in the type definition.
The hard part is out of the way, I just haven't had time to finish this yet. I'll get there soon™ :)
Actionable comments posted: 10
🧹 Nitpick comments (4)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between
fc2ff11675and8ae7d6d96f.📒 Files selected for processing (22)
cards/.latestId(1 hunks)cards/Classes/Neutral/Collectible/Minions/10-Cost/104-yogg-saron-master-of-fate.ts(1 hunks)cards/Classes/Neutral/Uncollectible/Enchantments/0-Cost/144-fates-blessing.ts(1 hunks)cards/Examples/4/2a-enchantments.ts(1 hunks)cards/Examples/4/2b-enchantment-apply.ts(3 hunks)cards/Examples/4/lasta-enchantment.ts(1 hunks)cards/Examples/4/lastb-combined.ts(2 hunks)cards/Examples/Test/enchantment-apply.ts(1 hunks)cards/Examples/Test/enchantment.ts(1 hunks)cards/Galakrond/Rogue/145-galakronds-blessing.ts(1 hunks)cards/Galakrond/Rogue/67-hero.ts(1 hunks)cards/ids.ts(2 hunks)src/card.ts(8 hunks)src/event.ts(1 hunks)src/functions/card.ts(2 hunks)src/functions/util.ts(2 hunks)src/game.ts(1 hunks)src/player.ts(1 hunks)src/types/card.ts(8 hunks)tools/cardcreator/custom.ts(3 hunks)tools/cardcreator/lib.ts(9 hunks)tools/cardcreator/vanilla.ts(2 hunks)🧰 Additional context used
🧬 Code graph analysis (13)
cards/Examples/4/lasta-enchantment.ts (5)
cards/Examples/4/2a-enchantments.ts (4)
cards/Classes/Neutral/Uncollectible/Enchantments/0-Cost/144-fates-blessing.ts (3)
cards/Examples/Test/enchantment.ts (4)
src/functions/util.ts (2)
cards/Galakrond/Rogue/145-galakronds-blessing.ts (3)
cards/Examples/Test/enchantment-apply.ts (2)
src/functions/card.ts (1)
tools/cardcreator/custom.ts (3)
tools/cardcreator/lib.ts (1)
src/game.ts (1)
src/types/card.ts (3)
src/card.ts (1)
🔇 Additional comments (18)
@ -0,0 +1,49 @@// Created by the Custom Card Creator⚠️ Potential issue | 🟠 Major
Empty
enchantmentRemovedoes not restore original cost.Similar to
galakronds-blessing.ts, this enchantment'senchantmentRemoveis a no-op, leaving the cost at 0 permanently. If this enchantment is temporary (e.g., "costs (0) this turn" as seen in Yogg-Saron usage), the cost should be restored.Based on the usage in
cards/Classes/Neutral/Collectible/Minions/10-Cost/104-yogg-saron-master-of-fate.ts, this enchantment is explicitly removed at end of turn, so it needs to restore the original cost:📝 Committable suggestion
🤖 Prompt for AI Agents
✅ Addressed in commit
5f0b8db@ -0,0 +68,4 @@assert.equal(target?.attack, originalTargetAttack! + 1);assert.equal(target?.health, originalTargetHealth! + 2);},⚠️ Potential issue | 🔴 Critical
Critical test assertion bug.
Lines 69-70 contain incorrect variable references in the assertions:
target?.attacktooriginalTargetHealth! + 1(should beoriginalTargetAttack! + 1)Apply this diff to fix the test assertions:
📝 Committable suggestion
🤖 Prompt for AI Agents
✅ Addressed in commit
5f0b8db@ -0,0 +1,39 @@// Created by the Custom Card Creator⚠️ Potential issue | 🟡 Minor
Parameter order inconsistency.
This test method uses
(owner, self)parameter order, while other enchantment test methods in this PR use(self, owner). This inconsistency could indicate a copy-paste error.Apply this diff to match the standard parameter order:
📝 Committable suggestion
🤖 Prompt for AI Agents
✅ Addressed in commit
5f0b8db@ -0,0 +1,48 @@// Created by the Custom Card Creator⚠️ Potential issue | 🟠 Major
Empty
enchantmentRemovedoes not restore original cost.When the enchantment is removed, the host card's cost remains at 0 because
enchantmentRemoveis a no-op. If the enchantment is temporary, you should restore the cost or rely on refresh logic.If the enchantment needs to be reversible, consider storing the original cost and restoring it:
🤖 Prompt for AI Agents
⚠️ Potential issue | 🟡 Minor
Complete the field documentation.
The comment for
activeEnchantmentsis incomplete and contains empty code block markers.Apply this diff:
🤖 Prompt for AI Agents
✅ Addressed in commit
5f0b8db⚠️ Potential issue | 🔴 Critical
Critical: Sort order is inverted.
The sort order is ascending (
priorityA - priorityB), which applies LOWER priority enchantments first. However, the documentation (lines 196-199) states that "A higher priority means that the enchantment will be applied before others."Your own example confirms this: the "set attack to 0" enchantment (Highest priority) should be applied BEFORE the "+1 attack" enchantment (Normal priority), resulting in a final attack of 1, not 0.
With the current ascending sort:
With descending sort:
Apply this diff:
📝 Committable suggestion
🤖 Prompt for AI Agents
✅ Addressed in commit
5f0b8db⚠️ Potential issue | 🟠 Major
Missing await on async call.
Line 1527 calls
removeFromPlay()without awaiting it. SinceremoveFromPlay()is async and performs important cleanup (silencing, destroying, and removing the enchantment fromgame.activeCards), failing to await it can cause:refreshEnchantments()callgame.activeCardsnot being properly updated (relates to the unchecked PR objective)Apply this diff:
📝 Committable suggestion
🤖 Prompt for AI Agents
✅ Addressed in commit
5f0b8db@ -101,8 +101,8 @@ export const eventManager = {⚠️ Potential issue | 🔴 Critical
🧩 Analysis chain
Verify enchantment refresh is handled elsewhere.
The removal of per-tick enchantment application is a significant change. The commented line and note "Just in case. Remove for performance boost" suggests this may need revisiting. Please confirm:
According to the PR description, this is a known incomplete item: "Fix
game.activeCardsnot updating according to the enchantments" remains unchecked in the PR checklist.🏁 Script executed:
Length of output: 5848
is not applicable here as we need repository files.
🏁 Script executed:
Length of output: 636
🏁 Script executed:
Length of output: 160
🏁 Script executed:
Length of output: 1257
🏁 Script executed:
Length of output: 16553
🏁 Script executed:
Length of output: 5335
Confirm enchantment refresh handling for mid-game state changes.
The removal of per-tick enchantment refresh creates a gap: methods that modify card state (
addKeyword(),removeKeyword(),setStats()) do not triggerrefreshEnchantments(). Enchantment effects are now only re-applied when:If enchantment effects conditionally depend on card state (keywords, stats), they will not update when that state changes during gameplay through other means. This aligns with the PR checklist item "Fix
game.activeCardsnot updating according to the enchantments" remaining unchecked.Verify that enchantments do not have state-dependent conditional logic, or add refresh calls to
addKeyword(),removeKeyword(), and stat modification methods that could affect active enchantments.🤖 Prompt for AI Agents
✅ Addressed in commit
5f0b8db⚠️ Potential issue | 🔴 Critical
Type mismatch in requiredFieldsTable.
Lines 278 and 279-283 use
Abilityenum values instead of string keys matchingBlueprintproperty names. TherequiredFieldsTableexpects(keyof Blueprint)[], but abilities are stored as methods on the blueprint (e.g.,heropower,enchantmentApply,enchantmentRemove), not asAbilityenum values.Apply this diff to use the correct property names:
📝 Committable suggestion
🤖 Prompt for AI Agents
@ -296,27 +317,43 @@ ${runes}${keywords}}⚠️ Potential issue | 🟠 Major
Clamp invalid enchantment priorities before emitting code.
If a creator types an out-of-range value (e.g.
3) the emitted file containsEnchantmentPriority.undefined, which fails to compile and breaks the workflow. Please sanitize the number before stringifying so we always output a real enum member.✅ Addressed in commit
5f0b8dbActionable comments posted: 0
♻️ Duplicate comments (1)
🧹 Nitpick comments (2)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between
8ae7d6d96fand5f0b8dbbf5.📒 Files selected for processing (10)
cards/Classes/Neutral/Uncollectible/Enchantments/0-Cost/144-fates-blessing.ts(1 hunks)cards/Examples/4/2a-enchantments.ts(1 hunks)cards/Examples/Test/enchantment-apply.ts(1 hunks)cards/Examples/Test/enchantment.ts(1 hunks)cards/Galakrond/Rogue/145-galakronds-blessing.ts(1 hunks)scripts/test/crash.ts(1 hunks)src/card.ts(8 hunks)src/event.ts(1 hunks)src/types/card.ts(8 hunks)tools/cardcreator/lib.ts(9 hunks)🚧 Files skipped from review as they are similar to previous changes (4)
🧰 Additional context used
🧬 Code graph analysis (5)
tools/cardcreator/lib.ts (2)
cards/Galakrond/Rogue/145-galakronds-blessing.ts (5)
src/types/card.ts (3)
cards/Examples/4/2a-enchantments.ts (5)
src/card.ts (1)
🔇 Additional comments (11)