forked from External/mage
move findTargetingStackObject from CardUtil to Game, so saved data can be cleared with short living lki add test cases
This commit is contained in:
parent
030e8ae5d3
commit
24f030fa71
13 changed files with 181 additions and 73 deletions
|
|
@ -44,7 +44,6 @@ import mage.game.permanent.PermanentMeld;
|
|||
import mage.game.permanent.PermanentToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
import mage.players.PlayerList;
|
||||
import mage.target.Target;
|
||||
|
|
@ -1133,49 +1132,6 @@ public final class CardUtil {
|
|||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* For finding the spell or ability on the stack for "becomes the target" triggers.
|
||||
* Also ensures that spells/abilities that target the same object twice only trigger each "becomes the target" ability once.
|
||||
* If this is the first attempt at triggering for a given ability targeting a given object,
|
||||
* this method records that in the game state for later checks by this same method, to not return the same object again.
|
||||
*
|
||||
* @param checkingReference must be unique for each usage (this.getId().toString() of the TriggeredAbility, or this.getKey() of the watcher)
|
||||
* @param event the GameEvent.EventType.TARGETED from checkTrigger() or watch()
|
||||
* @param game the Game from checkTrigger() or watch()
|
||||
* @return the StackObject which targeted the source, or null if already used or not found
|
||||
*/
|
||||
public static StackObject findTargetingStackObject(String checkingReference, GameEvent event, Game game) {
|
||||
// In case of multiple simultaneous triggered abilities from the same source,
|
||||
// need to get the actual one that targeted, see #8026, #8378, rulings for Battle Mammoth
|
||||
// In case of copied triggered abilities, need to trigger on each independently, see #13498
|
||||
// Also avoids triggering on cancelled selections, see #8802
|
||||
String stateKey = "targetedMap" + checkingReference;
|
||||
Map<UUID, Set<UUID>> targetMap = (Map<UUID, Set<UUID>>) game.getState().getValue(stateKey);
|
||||
// targetMap: key - targetId; value - Set of stackObject Ids
|
||||
if (targetMap == null) {
|
||||
targetMap = new HashMap<>();
|
||||
} else {
|
||||
targetMap = new HashMap<>(targetMap); // must have new object reference if saved back to game state
|
||||
}
|
||||
Set<UUID> targetingObjects = targetMap.computeIfAbsent(event.getTargetId(), k -> new HashSet<>());
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
Ability stackAbility = stackObject.getStackAbility();
|
||||
if (stackAbility == null || !stackAbility.getSourceId().equals(event.getSourceId())) {
|
||||
continue;
|
||||
}
|
||||
if (CardUtil.getAllSelectedTargets(stackAbility, game).contains(event.getTargetId())) {
|
||||
if (!targetingObjects.add(stackObject.getId())) {
|
||||
continue; // The trigger/watcher already recorded that target of the stack object, check for another
|
||||
}
|
||||
// Otherwise, store this combination of trigger/watcher + target + stack object
|
||||
targetMap.put(event.getTargetId(), targetingObjects);
|
||||
game.getState().setValue(stateKey, targetMap);
|
||||
return stackObject;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* For overriding `canTarget()` with usages such as "any number of target cards with total mana value X or less".
|
||||
* Call this after super.canTarget() returns true.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue