magefree / magefree/mage

Non-stack delayed triggers must be reworked?

Open
#12,111 3 comments 0 reactions 0 assignees View on GitHub
bug refactoring
Dominant language
Java
Stars
2.4k
Forks
940
Avg merge
2d 12h
Merged PRs (30d)
160

Description

It's not a critical problem, can be related to some rare bugs with commander moves, counters conditional and other state base things. See example: #4025

**Affected cards**

[[Banisher Priest]], [[Grasp of Fate]] and other with rules like "exile ... until {this} leaves the battlefield". Search problem cards by `usesStack = false` or `new OnLeaveReturnExiledAbility`.
![shot_240411_222040](https://github.com/magefree/mage/assets/8344157/5c53ca95-3dc5-4bc0-89b7-afdf58a1b26c)

**Problem**

Current code do not support full rules like "nothing happens between the two events, including state-based actions" (see related test in `StateBaseTriggeredAbilityTest::test_GraspOfFate_DelayedTriggerMustResolveImmediately`).

Non-stack delayed triggers are xmage's workaround to support specific cards instead replacement effects usage. I don't find any [MTG rules about non-stack triggers](https://mtg.fandom.com/wiki/Triggered_ability). That effects must be resolved immediately like mana abilities does -- but it uses triggers lifecycle instead (all triggered collects in shared list and executes one by one on new game cycle).

Related rules:

> Banisher Priest's ability causes a zone change with a duration, a new style of ability that's somewhat reminiscent of older cards like Oblivion Ring. However, unlike Oblivion Ring, cards like Banisher Priest have a single ability that creates two one-shot effects: one that exiles the creature when the ability resolves, and another that returns the exiled card to the battlefield immediately after Banisher Priest leaves the battlefield. (2013-07-01)

> The exiled card returns to the battlefield immediately after Banisher Priest leaves the battlefield. Nothing happens between the two events, including state-based actions. The two creatures aren't on the battlefield at the same time. For example, if the returning creature is a Clone, it can't enter the battlefield as a copy of Banisher Priest. (2013-07-01)

> In a multiplayer game, if Grasp of Fate's owner leaves the game, the exiled cards will return to the battlefield. Because the one-shot effect that returns the cards isn't an ability that goes on the stack, it won't cease to exist along with the leaving player's spells and abilities on the stack. (2015-11-04)

**Possible solutions**

I'm tried to fix it by immediately resolve like mana abilities does but it not work due new game cycle usage (`ApplyEffects`) on active/resolve. See details docs by code search `state.addTriggeredAbility` or related commit 367defd9958ac88b28206c6841771a71ee9b3ef5.

So only cards rework can help here. All related cards must migrate to existing replacement effects due card rules (example replacement effect on zone move). Make sure it support resolve on controller leave (delayed triggers does). The last one very important feature of delayed triggers: #4025.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with StateBaseTriggeredAbilityTest::test_GraspOfFate_DelayedTriggerMustResolveImmediately and inspect affected cards found through usesStack = false or OnLeaveReturnExiledAbility. Trace state.addTriggeredAbility and ApplyEffects, along with commit 367defd9958ac88b28206c6841771a71ee9b3ef5. Done means related cards use replacement effects while preserving immediate returns when a controller leaves the game.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend, game-dev
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.