* Genesis Ultimatum - fixed rollback error on usage with modal double faces cards (#7275);

This commit is contained in:
Oleg Agafonov 2020-12-23 09:15:04 +04:00
parent 796c8fb22e
commit 10cf9c4a4e
9 changed files with 94 additions and 46 deletions

View file

@ -90,6 +90,14 @@ public interface Game extends MageItem, Serializable {
Spell getSpellOrLKIStack(UUID spellId);
/**
* Find permanent on the battlefield by id. If you works with cards and want to check it on battlefield then
* use game.getState().getZone() instead. Card's id and permanent's id can be different (example: mdf card
* puts half card to battlefield, not the main card).
*
* @param permanentId
* @return
*/
Permanent getPermanent(UUID permanentId);
Permanent getPermanentOrLKIBattlefield(UUID permanentId);

View file

@ -342,7 +342,6 @@ public abstract class GameImpl implements Game, Serializable {
MageObject object;
if (state.getBattlefield().containsPermanent(objectId)) {
object = state.getBattlefield().getPermanent(objectId);
// state.setZone(objectId, Zone.BATTLEFIELD); // why is this neccessary?
return object;
}
if (getPermanentsEntering().containsKey(objectId)) {
@ -350,7 +349,6 @@ public abstract class GameImpl implements Game, Serializable {
}
for (StackObject item : state.getStack()) {
if (item.getId().equals(objectId)) {
// state.setZone(objectId, Zone.STACK); // why is this neccessary?
return item;
}
if (item.getSourceId().equals(objectId) && item instanceof Spell) {

View file

@ -167,8 +167,8 @@ public class GameState implements Serializable, Copyable<GameState> {
this.values.put(entry.getKey(), ((HashSet) entry.getValue()).clone());
} else if (entry.getValue() instanceof EnumSet) {
this.values.put(entry.getKey(), ((EnumSet) entry.getValue()).clone());
} else if (entry.getValue() instanceof HashMap){
this.values.put(entry.getKey(), ((HashMap) entry.getValue()).clone());
} else if (entry.getValue() instanceof HashMap) {
this.values.put(entry.getKey(), ((HashMap) entry.getValue()).clone());
} else {
this.values.put(entry.getKey(), entry.getValue());
}
@ -696,9 +696,7 @@ public class GameState implements Serializable, Copyable<GameState> {
public Permanent getPermanent(UUID permanentId) {
if (permanentId != null && battlefield.containsPermanent(permanentId)) {
Permanent permanent = battlefield.getPermanent(permanentId);
// setZone(permanent.getId(), Zone.BATTLEFIELD); // shouldn't this be set anyway? (LevelX2)
return permanent;
return battlefield.getPermanent(permanentId);
}
return null;
}

View file

@ -1,15 +1,16 @@
package mage.game.permanent;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import mage.abilities.keyword.PhasingAbility;
import mage.constants.CardType;
import mage.constants.RangeOfInfluence;
import mage.filter.FilterPermanent;
import mage.game.Game;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -57,8 +58,8 @@ public class Battlefield implements Serializable {
return (int) field.values()
.stream()
.filter(permanent -> permanent.isControlledBy(controllerId)
&& filter.match(permanent, game)
&& permanent.isPhasedIn())
&& filter.match(permanent, game)
&& permanent.isPhasedIn())
.count();
}
@ -68,8 +69,8 @@ public class Battlefield implements Serializable {
* influence of the specified player id and that match the supplied filter.
*
* @param filter
* @param sourceId - sourceId of the MageObject the calling effect/ability
* belongs to
* @param sourceId - sourceId of the MageObject the calling effect/ability
* belongs to
* @param sourcePlayerId
* @param game
* @return count
@ -79,15 +80,15 @@ public class Battlefield implements Serializable {
return (int) field.values()
.stream()
.filter(permanent -> filter.match(permanent, sourceId, sourcePlayerId, game)
&& permanent.isPhasedIn())
&& permanent.isPhasedIn())
.count();
} else {
List<UUID> range = game.getState().getPlayersInRange(sourcePlayerId, game);
return (int) field.values()
.stream()
.filter(permanent -> range.contains(permanent.getControllerId())
&& filter.match(permanent, sourceId, sourcePlayerId, game)
&& permanent.isPhasedIn()).count();
&& filter.match(permanent, sourceId, sourcePlayerId, game)
&& permanent.isPhasedIn()).count();
}
}
@ -104,7 +105,7 @@ public class Battlefield implements Serializable {
return field.values()
.stream()
.filter(permanent -> filter.match(permanent, game)
&& permanent.isPhasedIn()).count() >= num;
&& permanent.isPhasedIn()).count() >= num;
}
@ -123,8 +124,8 @@ public class Battlefield implements Serializable {
return field.values()
.stream()
.filter(permanent -> permanent.isControlledBy(controllerId)
&& filter.match(permanent, game)
&& permanent.isPhasedIn())
&& filter.match(permanent, game)
&& permanent.isPhasedIn())
.count() >= num;
}
@ -144,14 +145,14 @@ public class Battlefield implements Serializable {
if (game.getRangeOfInfluence() == RangeOfInfluence.ALL) {
return field.values().stream()
.filter(permanent -> filter.match(permanent, null, sourcePlayerId, game)
&& permanent.isPhasedIn()).count() >= num;
&& permanent.isPhasedIn()).count() >= num;
} else {
List<UUID> range = game.getState().getPlayersInRange(sourcePlayerId, game);
return field.values().stream()
.filter(permanent -> range.contains(permanent.getControllerId())
&& filter.match(permanent, null, sourcePlayerId, game)
&& permanent.isPhasedIn())
&& filter.match(permanent, null, sourcePlayerId, game)
&& permanent.isPhasedIn())
.count() >= num;
}
}
@ -168,6 +169,14 @@ public class Battlefield implements Serializable {
field.remove(key);
}
/**
* Find permanent on the battlefield by id. If you works with cards and want to check it on battlefield then
* use game.getState().getZone() instead. Card's id and permanent's id can be different (example: mdf card
* puts half card to battlefield, not the main card).
*
* @param key
* @return
*/
public boolean containsPermanent(UUID key) {
return field.containsKey(key);
}
@ -211,7 +220,7 @@ public class Battlefield implements Serializable {
return field.values()
.stream()
.filter(perm -> perm.isPhasedIn()
&& perm.isControlledBy(controllerId))
&& perm.isControlledBy(controllerId))
.collect(Collectors.toList());
}
@ -300,7 +309,7 @@ public class Battlefield implements Serializable {
return field.values()
.stream()
.filter(perm -> perm.isPhasedIn() && range.contains(perm.getControllerId())
&& filter.match(perm, sourceId, sourcePlayerId, game)).collect(Collectors.toList());
&& filter.match(perm, sourceId, sourcePlayerId, game)).collect(Collectors.toList());
}
}
@ -321,7 +330,7 @@ public class Battlefield implements Serializable {
return field.values()
.stream()
.filter(perm -> perm.isPhasedIn()
&& range.contains(perm.getControllerId()))
&& range.contains(perm.getControllerId()))
.collect(Collectors.toList());
}
@ -331,8 +340,8 @@ public class Battlefield implements Serializable {
return field.values()
.stream()
.filter(perm -> perm.hasAbility(PhasingAbility.getInstance(), game)
&& perm.isPhasedIn()
&& perm.isControlledBy(controllerId))
&& perm.isPhasedIn()
&& perm.isControlledBy(controllerId))
.collect(Collectors.toList());
}