mirror of
https://github.com/correl/mage.git
synced 2024-11-25 03:00:11 +00:00
Cheat engine: fixed that it doesn't init effects and other staff from battlefield permanents (#6888);
This commit is contained in:
parent
e5529d5835
commit
96155ec799
4 changed files with 86 additions and 55 deletions
|
@ -22,6 +22,7 @@ import mage.game.command.CommandObject;
|
||||||
import mage.game.command.Plane;
|
import mage.game.command.Plane;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
import mage.util.CardUtil;
|
||||||
import mage.util.RandomUtil;
|
import mage.util.RandomUtil;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -572,7 +573,7 @@ public final class SystemUtil {
|
||||||
|
|
||||||
// move card from exile to stack
|
// move card from exile to stack
|
||||||
for (Card card : cardsToLoad) {
|
for (Card card : cardsToLoad) {
|
||||||
swapWithAnyCard(game, player, card, Zone.STACK);
|
putCardToZone(game, player, card, Zone.STACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -647,7 +648,7 @@ public final class SystemUtil {
|
||||||
} else {
|
} else {
|
||||||
// as other card
|
// as other card
|
||||||
for (Card card : cardsToLoad) {
|
for (Card card : cardsToLoad) {
|
||||||
swapWithAnyCard(game, player, card, gameZone);
|
putCardToZone(game, player, card, gameZone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -657,38 +658,33 @@ public final class SystemUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Swap cards between specified card from library and any hand card.
|
* Put card to specified (battlefield zone will be tranformed to permanent with initialized effects)
|
||||||
*
|
|
||||||
* @param game
|
|
||||||
* @param card Card to put to player's hand
|
|
||||||
*/
|
*/
|
||||||
private static void swapWithAnyCard(Game game, Player player, Card card, Zone zone) {
|
private static void putCardToZone(Game game, Player player, Card card, Zone zone) {
|
||||||
// Put the card in Exile to start. Otherwise the game doesn't know where to remove the card from.
|
// TODO: replace by player.move?
|
||||||
game.getExile().getPermanentExile().add(card);
|
|
||||||
game.setZone(card.getId(), Zone.EXILED);
|
|
||||||
switch (zone) {
|
switch (zone) {
|
||||||
case BATTLEFIELD:
|
case BATTLEFIELD:
|
||||||
card.putOntoBattlefield(game, Zone.EXILED, null, player.getId());
|
CardUtil.putCardOntoBattlefieldWithEffects(game, card, player);
|
||||||
break;
|
break;
|
||||||
case LIBRARY:
|
case LIBRARY:
|
||||||
card.setZone(Zone.LIBRARY, game);
|
card.setZone(Zone.LIBRARY, game);
|
||||||
game.getExile().getPermanentExile().remove(card);
|
|
||||||
player.getLibrary().putOnTop(card, game);
|
player.getLibrary().putOnTop(card, game);
|
||||||
break;
|
break;
|
||||||
case STACK:
|
case STACK:
|
||||||
card.cast(game, Zone.EXILED, card.getSpellAbility(), player.getId());
|
card.cast(game, game.getState().getZone(card.getId()), card.getSpellAbility(), player.getId());
|
||||||
break;
|
break;
|
||||||
case EXILED:
|
case EXILED:
|
||||||
// nothing to do
|
card.setZone(Zone.EXILED, game);
|
||||||
|
game.getExile().getPermanentExile().add(card);
|
||||||
break;
|
break;
|
||||||
case OUTSIDE:
|
case OUTSIDE:
|
||||||
card.setZone(Zone.OUTSIDE, game);
|
card.setZone(Zone.OUTSIDE, game);
|
||||||
game.getExile().getPermanentExile().remove(card);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
card.moveToZone(zone, null, game, false);
|
card.moveToZone(zone, null, game, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
game.applyEffects();
|
||||||
logger.info("Added card to player's " + zone.toString() + ": " + card.getName() + ", player = " + player.getName());
|
logger.info("Added card to player's " + zone.toString() + ": " + card.getName() + ", player = " + player.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package mage.game;
|
package mage.game;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import mage.MageException;
|
import mage.MageException;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.abilities.*;
|
import mage.abilities.*;
|
||||||
|
@ -64,6 +60,7 @@ import mage.target.Target;
|
||||||
import mage.target.TargetCard;
|
import mage.target.TargetCard;
|
||||||
import mage.target.TargetPermanent;
|
import mage.target.TargetPermanent;
|
||||||
import mage.target.TargetPlayer;
|
import mage.target.TargetPlayer;
|
||||||
|
import mage.util.CardUtil;
|
||||||
import mage.util.GameLog;
|
import mage.util.GameLog;
|
||||||
import mage.util.MessageToClient;
|
import mage.util.MessageToClient;
|
||||||
import mage.util.RandomUtil;
|
import mage.util.RandomUtil;
|
||||||
|
@ -71,6 +68,11 @@ import mage.util.functions.ApplyToPermanent;
|
||||||
import mage.watchers.common.*;
|
import mage.watchers.common.*;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
public abstract class GameImpl implements Game, Serializable {
|
public abstract class GameImpl implements Game, Serializable {
|
||||||
|
|
||||||
private static final int ROLLBACK_TURNS_MAX = 4;
|
private static final int ROLLBACK_TURNS_MAX = 4;
|
||||||
|
@ -1805,7 +1807,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// triggered abilities that don't use the stack have to be executed first (e.g. Banisher Priest Return exiled creature
|
// triggered abilities that don't use the stack have to be executed first (e.g. Banisher Priest Return exiled creature
|
||||||
for (Iterator<TriggeredAbility> it = abilities.iterator(); it.hasNext();) {
|
for (Iterator<TriggeredAbility> it = abilities.iterator(); it.hasNext(); ) {
|
||||||
TriggeredAbility triggeredAbility = it.next();
|
TriggeredAbility triggeredAbility = it.next();
|
||||||
if (!triggeredAbility.isUsesStack()) {
|
if (!triggeredAbility.isUsesStack()) {
|
||||||
state.removeTriggeredAbility(triggeredAbility);
|
state.removeTriggeredAbility(triggeredAbility);
|
||||||
|
@ -2602,7 +2604,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
}
|
}
|
||||||
//20100423 - 800.4a
|
//20100423 - 800.4a
|
||||||
Set<Card> toOutside = new HashSet<>();
|
Set<Card> toOutside = new HashSet<>();
|
||||||
for (Iterator<Permanent> it = getBattlefield().getAllPermanents().iterator(); it.hasNext();) {
|
for (Iterator<Permanent> it = getBattlefield().getAllPermanents().iterator(); it.hasNext(); ) {
|
||||||
Permanent perm = it.next();
|
Permanent perm = it.next();
|
||||||
if (perm.isOwnedBy(playerId)) {
|
if (perm.isOwnedBy(playerId)) {
|
||||||
if (perm.getAttachedTo() != null) {
|
if (perm.getAttachedTo() != null) {
|
||||||
|
@ -2652,7 +2654,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
player.moveCards(toOutside, Zone.OUTSIDE, null, this);
|
player.moveCards(toOutside, Zone.OUTSIDE, null, this);
|
||||||
// triggered abilities that don't use the stack have to be executed
|
// triggered abilities that don't use the stack have to be executed
|
||||||
List<TriggeredAbility> abilities = state.getTriggered(player.getId());
|
List<TriggeredAbility> abilities = state.getTriggered(player.getId());
|
||||||
for (Iterator<TriggeredAbility> it = abilities.iterator(); it.hasNext();) {
|
for (Iterator<TriggeredAbility> it = abilities.iterator(); it.hasNext(); ) {
|
||||||
TriggeredAbility triggeredAbility = it.next();
|
TriggeredAbility triggeredAbility = it.next();
|
||||||
if (!triggeredAbility.isUsesStack()) {
|
if (!triggeredAbility.isUsesStack()) {
|
||||||
state.removeTriggeredAbility(triggeredAbility);
|
state.removeTriggeredAbility(triggeredAbility);
|
||||||
|
@ -2672,7 +2674,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
|
|
||||||
// Remove cards from the player in all exile zones
|
// Remove cards from the player in all exile zones
|
||||||
for (ExileZone exile : this.getExile().getExileZones()) {
|
for (ExileZone exile : this.getExile().getExileZones()) {
|
||||||
for (Iterator<UUID> it = exile.iterator(); it.hasNext();) {
|
for (Iterator<UUID> it = exile.iterator(); it.hasNext(); ) {
|
||||||
Card card = this.getCard(it.next());
|
Card card = this.getCard(it.next());
|
||||||
if (card != null && card.isOwnedBy(playerId)) {
|
if (card != null && card.isOwnedBy(playerId)) {
|
||||||
it.remove();
|
it.remove();
|
||||||
|
@ -2682,7 +2684,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
|
|
||||||
//Remove all commander/emblems/plane the player controls
|
//Remove all commander/emblems/plane the player controls
|
||||||
boolean addPlaneAgain = false;
|
boolean addPlaneAgain = false;
|
||||||
for (Iterator<CommandObject> it = this.getState().getCommand().iterator(); it.hasNext();) {
|
for (Iterator<CommandObject> it = this.getState().getCommand().iterator(); it.hasNext(); ) {
|
||||||
CommandObject obj = it.next();
|
CommandObject obj = it.next();
|
||||||
if (obj.isControlledBy(playerId)) {
|
if (obj.isControlledBy(playerId)) {
|
||||||
if (obj instanceof Emblem) {
|
if (obj instanceof Emblem) {
|
||||||
|
@ -3063,28 +3065,10 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
throw new IllegalArgumentException("Command zone supports in commander test games");
|
throw new IllegalArgumentException("Command zone supports in commander test games");
|
||||||
}
|
}
|
||||||
|
|
||||||
// warning, permanents go to battlefield without resolve, continuus effects must be init
|
|
||||||
for (PermanentCard permanentCard : battlefield) {
|
for (PermanentCard permanentCard : battlefield) {
|
||||||
permanentCard.setZone(Zone.BATTLEFIELD, this);
|
CardUtil.putCardOntoBattlefieldWithEffects(this, permanentCard, player);
|
||||||
permanentCard.setOwnerId(ownerId);
|
|
||||||
PermanentCard newPermanent = new PermanentCard(permanentCard.getCard(), ownerId, this);
|
|
||||||
getPermanentsEntering().put(newPermanent.getId(), newPermanent);
|
|
||||||
newPermanent.entersBattlefield(newPermanent.getId(), this, Zone.OUTSIDE, false);
|
|
||||||
addPermanent(newPermanent, getState().getNextPermanentOrderNumber());
|
|
||||||
getPermanentsEntering().remove(newPermanent.getId());
|
|
||||||
newPermanent.removeSummoningSickness();
|
|
||||||
if (permanentCard.isTapped()) {
|
|
||||||
newPermanent.setTapped(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// init effects on static abilities (init continuous effects, warning, game state contains copy)
|
|
||||||
for (ContinuousEffect effect : this.getState().getContinuousEffects().getLayeredEffects(this)) {
|
|
||||||
Optional<Ability> ability = this.getState().getContinuousEffects().getLayeredEffectAbilities(effect).stream().findFirst();
|
|
||||||
if (ability.isPresent() && newPermanent.getId().equals(ability.get().getSourceId())) {
|
|
||||||
effect.init(ability.get(), this, activePlayerId); // game is not setup yet, game.activePlayer is null -- need direct id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
applyEffects();
|
applyEffects();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package mage.game;
|
package mage.game;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.Cards;
|
import mage.cards.Cards;
|
||||||
import mage.cards.CardsImpl;
|
import mage.cards.CardsImpl;
|
||||||
|
@ -19,6 +18,8 @@ import mage.game.stack.Spell;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.target.TargetCard;
|
import mage.target.TargetCard;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by samuelsandeen on 9/6/16.
|
* Created by samuelsandeen on 9/6/16.
|
||||||
*/
|
*/
|
||||||
|
@ -52,7 +53,7 @@ public final class ZonesHandler {
|
||||||
|
|
||||||
public static List<ZoneChangeInfo> moveCards(List<ZoneChangeInfo> zoneChangeInfos, Game game) {
|
public static List<ZoneChangeInfo> moveCards(List<ZoneChangeInfo> zoneChangeInfos, Game game) {
|
||||||
// Handle Unmelded Meld Cards
|
// Handle Unmelded Meld Cards
|
||||||
for (ListIterator<ZoneChangeInfo> itr = zoneChangeInfos.listIterator(); itr.hasNext();) {
|
for (ListIterator<ZoneChangeInfo> itr = zoneChangeInfos.listIterator(); itr.hasNext(); ) {
|
||||||
ZoneChangeInfo info = itr.next();
|
ZoneChangeInfo info = itr.next();
|
||||||
MeldCard card = game.getMeldCard(info.event.getTargetId());
|
MeldCard card = game.getMeldCard(info.event.getTargetId());
|
||||||
// Copies should be handled as normal cards.
|
// Copies should be handled as normal cards.
|
||||||
|
@ -201,7 +202,7 @@ public final class ZonesHandler {
|
||||||
if (info instanceof ZoneChangeInfo.Unmelded) {
|
if (info instanceof ZoneChangeInfo.Unmelded) {
|
||||||
ZoneChangeInfo.Unmelded unmelded = (ZoneChangeInfo.Unmelded) info;
|
ZoneChangeInfo.Unmelded unmelded = (ZoneChangeInfo.Unmelded) info;
|
||||||
MeldCard meld = game.getMeldCard(info.event.getTargetId());
|
MeldCard meld = game.getMeldCard(info.event.getTargetId());
|
||||||
for (Iterator<ZoneChangeInfo> itr = unmelded.subInfo.iterator(); itr.hasNext();) {
|
for (Iterator<ZoneChangeInfo> itr = unmelded.subInfo.iterator(); itr.hasNext(); ) {
|
||||||
ZoneChangeInfo subInfo = itr.next();
|
ZoneChangeInfo subInfo = itr.next();
|
||||||
if (!maybeRemoveFromSourceZone(subInfo, game)) {
|
if (!maybeRemoveFromSourceZone(subInfo, game)) {
|
||||||
itr.remove();
|
itr.remove();
|
||||||
|
@ -233,6 +234,7 @@ public final class ZonesHandler {
|
||||||
if (!game.replaceEvent(event)) {
|
if (!game.replaceEvent(event)) {
|
||||||
Zone fromZone = event.getFromZone();
|
Zone fromZone = event.getFromZone();
|
||||||
if (event.getToZone() == Zone.BATTLEFIELD) {
|
if (event.getToZone() == Zone.BATTLEFIELD) {
|
||||||
|
// prepare card and permanent
|
||||||
// If needed take attributes from the spell (e.g. color of spell was changed)
|
// If needed take attributes from the spell (e.g. color of spell was changed)
|
||||||
card = takeAttributesFromSpell(card, event, game);
|
card = takeAttributesFromSpell(card, event, game);
|
||||||
// controlling player can be replaced so use event player now
|
// controlling player can be replaced so use event player now
|
||||||
|
@ -245,15 +247,18 @@ public final class ZonesHandler {
|
||||||
} else {
|
} else {
|
||||||
permanent = new PermanentCard(card, event.getPlayerId(), game);
|
permanent = new PermanentCard(card, event.getPlayerId(), game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// put onto battlefield with possible counters
|
||||||
game.getPermanentsEntering().put(permanent.getId(), permanent);
|
game.getPermanentsEntering().put(permanent.getId(), permanent);
|
||||||
card.checkForCountersToAdd(permanent, game);
|
card.checkForCountersToAdd(permanent, game);
|
||||||
permanent.setTapped(
|
permanent.setTapped(info instanceof ZoneChangeInfo.Battlefield
|
||||||
info instanceof ZoneChangeInfo.Battlefield && ((ZoneChangeInfo.Battlefield) info).tapped);
|
&& ((ZoneChangeInfo.Battlefield) info).tapped);
|
||||||
permanent.setFaceDown(info.faceDown, game);
|
|
||||||
|
|
||||||
|
permanent.setFaceDown(info.faceDown, game);
|
||||||
if (info.faceDown) {
|
if (info.faceDown) {
|
||||||
card.setFaceDown(false, game);
|
card.setFaceDown(false, game);
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure the controller of all continuous effects of this card are switched to the current controller
|
// make sure the controller of all continuous effects of this card are switched to the current controller
|
||||||
game.setScopeRelevant(true);
|
game.setScopeRelevant(true);
|
||||||
game.getContinuousEffects().setController(permanent.getId(), permanent.getControllerId());
|
game.getContinuousEffects().setController(permanent.getId(), permanent.getControllerId());
|
||||||
|
|
|
@ -8,18 +8,20 @@ import mage.abilities.Mode;
|
||||||
import mage.abilities.SpellAbility;
|
import mage.abilities.SpellAbility;
|
||||||
import mage.abilities.costs.VariableCost;
|
import mage.abilities.costs.VariableCost;
|
||||||
import mage.abilities.costs.mana.*;
|
import mage.abilities.costs.mana.*;
|
||||||
|
import mage.abilities.effects.ContinuousEffect;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.constants.ColoredManaSymbol;
|
import mage.cards.MeldCard;
|
||||||
import mage.constants.EmptyNames;
|
import mage.constants.*;
|
||||||
import mage.constants.ManaType;
|
|
||||||
import mage.constants.SpellAbilityType;
|
|
||||||
import mage.filter.Filter;
|
import mage.filter.Filter;
|
||||||
import mage.filter.predicate.mageobject.NamePredicate;
|
import mage.filter.predicate.mageobject.NamePredicate;
|
||||||
import mage.game.CardState;
|
import mage.game.CardState;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.game.permanent.PermanentCard;
|
||||||
|
import mage.game.permanent.PermanentMeld;
|
||||||
import mage.game.permanent.token.Token;
|
import mage.game.permanent.token.Token;
|
||||||
import mage.game.stack.Spell;
|
import mage.game.stack.Spell;
|
||||||
|
import mage.players.Player;
|
||||||
import mage.target.Target;
|
import mage.target.Target;
|
||||||
import mage.util.functions.CopyTokenFunction;
|
import mage.util.functions.CopyTokenFunction;
|
||||||
|
|
||||||
|
@ -829,4 +831,48 @@ public final class CardUtil {
|
||||||
.flatMap(Collection::stream)
|
.flatMap(Collection::stream)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put card to battlefield without resolve
|
||||||
|
*
|
||||||
|
* @param game
|
||||||
|
* @param card
|
||||||
|
* @param player
|
||||||
|
*/
|
||||||
|
public static void putCardOntoBattlefieldWithEffects(Game game, Card card, Player player) {
|
||||||
|
// same logic as ZonesHandler->maybeRemoveFromSourceZone
|
||||||
|
|
||||||
|
// prepare card and permanent
|
||||||
|
card.setZone(Zone.BATTLEFIELD, game);
|
||||||
|
card.setOwnerId(player.getId());
|
||||||
|
PermanentCard permanent;
|
||||||
|
if (card instanceof MeldCard) {
|
||||||
|
permanent = new PermanentMeld(card, player.getId(), game);
|
||||||
|
} else {
|
||||||
|
permanent = new PermanentCard(card, player.getId(), game);
|
||||||
|
}
|
||||||
|
|
||||||
|
// put onto battlefield with possible counters
|
||||||
|
game.getPermanentsEntering().put(permanent.getId(), permanent);
|
||||||
|
card.checkForCountersToAdd(permanent, game);
|
||||||
|
permanent.entersBattlefield(permanent.getId(), game, Zone.OUTSIDE, false);
|
||||||
|
game.addPermanent(permanent, game.getState().getNextPermanentOrderNumber());
|
||||||
|
game.getPermanentsEntering().remove(permanent.getId());
|
||||||
|
|
||||||
|
// workaround for special tapped status from test framework's command (addCard)
|
||||||
|
if (card instanceof PermanentCard && ((PermanentCard) card).isTapped()) {
|
||||||
|
permanent.setTapped(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove sickness
|
||||||
|
permanent.removeSummoningSickness();
|
||||||
|
|
||||||
|
// init effects on static abilities (init continuous effects; warning, game state contains copy)
|
||||||
|
for (ContinuousEffect effect : game.getState().getContinuousEffects().getLayeredEffects(game)) {
|
||||||
|
Optional<Ability> ability = game.getState().getContinuousEffects().getLayeredEffectAbilities(effect).stream().findFirst();
|
||||||
|
if (ability.isPresent() && permanent.getId().equals(ability.get().getSourceId())) {
|
||||||
|
effect.init(ability.get(), game, player.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue