Skip to content

fix(rooms): cast half enters unlocked, card art, no duplicate triggers - #15704

Open
maff1989 wants to merge 3 commits into
magefree:masterfrom
maff1989:enchantment-room-fixes
Open

fix(rooms): cast half enters unlocked, card art, no duplicate triggers#15704
maff1989 wants to merge 3 commits into
magefree:masterfrom
maff1989:enchantment-room-fixes

Conversation

@maff1989

Copy link
Copy Markdown
  • Casting a Room half now auto-unlocks that door on ETB as the rules require. Previously the permanent entered fully locked, neither half active, forcing manual re-unlock.

  • Card art now renders on the battlefield. The permanent's name is modified by RoomCharacteristicsEffect (showing only unlocked halves), but the client looked up card images by that modified name. Now uses the full split-card name from the blueprint. Additionally falls back to collector-ID-inclusive filenames for image sets that include them.

  • Fixed compounding trigger registrations. Room halves would fire 2× after first unlock, 3× after both unlocked. Three interacting bugs: restoreUnlockedStats() skipped game-state trigger registration for non-copy permanents; half-card triggered abilities leaked into the trigger map during game init; addRoomCharacteristics() re-registered all half abilities on every game-state reset cycle, duplicating the entries restoreUnlockedStats() had already re-added.

Tested in-game with Unholy Annex // Ritual Chamber and confirmed it is working. No other obvious splash damage introduced with these changes.

- Casting a Room half now auto-unlocks that door on ETB as the rules
  require. Previously the permanent entered fully locked, neither half
  active, forcing manual re-unlock.

- Card art now renders on the battlefield. The permanent's name is
  modified by RoomCharacteristicsEffect (showing only unlocked halves),
  but the client looked up card images by that modified name. Now uses
  the full split-card name from the blueprint. Additionally falls back
  to collector-ID-inclusive filenames for image sets that include them.

- Fixed compounding trigger registrations. Room halves would fire 2×
  after first unlock, 3× after both unlocked. Three interacting bugs:
  restoreUnlockedStats() skipped game-state trigger registration for
  non-copy permanents; half-card triggered abilities leaked into the
  trigger map during game init; addRoomCharacteristics() re-registered
  all half abilities on every game-state reset cycle, duplicating the
  entries restoreUnlockedStats() had already re-added.
@maff1989

Copy link
Copy Markdown
Author

I've done some further testing today and it appears this is NOT working anymore. I'm not sure what happened. I'll close this one and open a new one once I've done some further testing and verify it works consistently.

@maff1989 maff1989 closed this Jul 22, 2026
@maff1989
maff1989 deleted the enchantment-room-fixes branch July 22, 2026 04:35
@JayDi85

JayDi85 commented Jul 22, 2026

Copy link
Copy Markdown
Member

Create and use unit tests to check (it must fail on master and pass on PR).

It allow to collect client side info with image data -- so whole image part is testable. See example with RoomCardTest.java and getGameView(player) calls.

@JayDi85

JayDi85 commented Jul 22, 2026

Copy link
Copy Markdown
Member

For duplicated triggers - if it really duplicated somehow then unit tests will ask about triggers order and fail on miss choice on setStrictChooseMode(true). Another way to check it -- use runCode( and lookup inside game.getState().getTriggers() to manually check outdated-duplicated records -- same for any other objects like effects or abilities.

@Notshauna

Copy link
Copy Markdown

Yeah the current implementation of rooms is weird, in my experience it's inconsistent if the room enters unlocked or locked. It seems like it's something that is going to be challenging to resolve because of how strange a bug it is, because it varies card to card at least.

… permanent entries

RoomEnterUnlockEffect.apply() cleared lastCastHalf on the shared RoomCard
blueprint after the first ETB. This caused complex rooms (more triggers,
more applyEffects() cycles) to lose the cast-half info during state
reconstruction, while simple rooms with few effects could sometimes
squeak through — producing the card-to-card inconsistency the devs
observed.

Fix: delete the clear. ZonesHandler already clears lastCastHalf on zone
transitions (hand, graveyard, exile, library), covering all non-cast
entry paths. wasRoomUnlockedOnCast() on the permanent guards duplicate
unlocks.

- Removed roomCardBlueprint.setLastCastHalf(null)
- Collapsed return into bare unlockDoor() call
@maff1989 maff1989 reopened this Jul 24, 2026
@maff1989

Copy link
Copy Markdown
Author

Thanks for the info guys :) I re-opened this PR with an additional commit on the branch that has been working reliably in my local testing.

@matoro

matoro commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Thanks for the info guys :) I re-opened this PR with an additional commit on the branch that has been working reliably in my local testing.

There's lots of room-related regressions in the CI run, so your fix is not correct

…unlock

The RoomCard blueprint is a server-singleton shared across all permanents
of that card. After the ETB reads lastCastHalf to determine which door to
unlock, it must clear the value — otherwise stale cast-half data leaks into
copy permanents (Clever Impersonator, Sakashima) that share the same
blueprint. ZonesHandler already handles clearing on non-battlefield/stack
zone transitions; this clear covers the one remaining window during the ETB
itself. Game-state copies of already-unlocked permanents are guarded by
wasRoomUnlockedOnCast().

Also drops the unnecessary `return` from the unlockDoor() call.
EntersBattlefieldEffect.replaceEvent() ignores the return value of
effect.apply(), so returning unlockDoor()'s result was dead code.
@maff1989

Copy link
Copy Markdown
Author

Thanks @matoro, all 20 tests are passing now.

@matoro

matoro commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

can you please add a test that demonstrates the issue? it should fail on master and pass with your fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants