mirror of
https://github.com/magefree/mage.git
synced 2026-01-24 12:19:59 -08:00
* Some changes to zone object movement and source object handling. Origin source object of ability is now hold in ability to be able to check e.g. zone change counter.
This commit is contained in:
parent
4fe5560222
commit
b73f34a52e
32 changed files with 396 additions and 82 deletions
|
|
@ -476,5 +476,22 @@ public interface Ability extends Controllable, Serializable {
|
|||
void setCostModificationActive(boolean active);
|
||||
|
||||
boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game);
|
||||
|
||||
|
||||
/**
|
||||
* Sets the object that actually existed while a ability triggerd or
|
||||
* an ability was activated.
|
||||
*
|
||||
* @param mageObject
|
||||
*/
|
||||
void setSourceObject(MageObject mageObject);
|
||||
|
||||
/**
|
||||
* Returns the object that actually existed while a ability triggerd or
|
||||
* an ability was activated.
|
||||
* If not set yet, the current object will be retrieved from the game.
|
||||
*
|
||||
* @param game
|
||||
* @return
|
||||
*/
|
||||
MageObject getSourceObject(Game game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
protected boolean costModificationActive = true;
|
||||
protected boolean activated = false;
|
||||
protected boolean worksFaceDown = false;
|
||||
protected MageObject sourceObject;
|
||||
|
||||
public AbilityImpl(AbilityType abilityType, Zone zone) {
|
||||
this.id = UUID.randomUUID();
|
||||
|
|
@ -142,6 +143,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
this.costModificationActive = ability.costModificationActive;
|
||||
this.worksFaceDown = ability.worksFaceDown;
|
||||
this.abilityWord = ability.abilityWord;
|
||||
this.sourceObject = ability.sourceObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -230,7 +232,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
|
||||
// TODO: Because all (non targeted) choices have to be done during resolution
|
||||
// this has to be removed, if all using effects are changed
|
||||
MageObject sourceObject = game.getObject(sourceId);
|
||||
sourceObject = game.getObject(sourceId);
|
||||
if (sourceObject != null) {
|
||||
sourceObject.adjustChoices(this, game);
|
||||
}
|
||||
|
|
@ -1024,6 +1026,19 @@ public abstract class AbilityImpl implements Ability {
|
|||
this.worksFaceDown = worksFaceDown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MageObject getSourceObject(Game game) {
|
||||
if (sourceObject != null) {
|
||||
return sourceObject;
|
||||
} else {
|
||||
return game.getObject(sourceId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceObject(MageObject sourceObject) {
|
||||
this.sourceObject = sourceObject;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,5 +44,5 @@ public interface TriggeredAbility extends Ability {
|
|||
boolean checkTrigger(GameEvent event, Game game);
|
||||
boolean checkInterveningIfClause(Game game);
|
||||
TriggeredAbility copy();
|
||||
void setSourceObject(MageObject mageObject);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ import mage.players.Player;
|
|||
public abstract class TriggeredAbilityImpl extends AbilityImpl implements TriggeredAbility {
|
||||
|
||||
protected boolean optional;
|
||||
protected MageObject sourceObject;
|
||||
|
||||
public TriggeredAbilityImpl(Zone zone, Effect effect) {
|
||||
this(zone, effect, false);
|
||||
|
|
@ -152,12 +151,4 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
public MageObject getSourceObject() {
|
||||
return sourceObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceObject(MageObject sourceObject) {
|
||||
this.sourceObject = sourceObject;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ package mage.abilities.common;
|
|||
|
||||
import mage.constants.Zone;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
|||
|
|
@ -49,12 +49,16 @@ public class ZoneChangeTriggeredAbility extends TriggeredAbilityImpl {
|
|||
protected String rule;
|
||||
|
||||
public ZoneChangeTriggeredAbility(Zone fromZone, Zone toZone, Effect effect, String rule, boolean optional) {
|
||||
super(fromZone, effect, optional);
|
||||
this(fromZone, fromZone, toZone, effect, rule, optional);
|
||||
}
|
||||
|
||||
public ZoneChangeTriggeredAbility(Zone worksInZone, Zone fromZone, Zone toZone, Effect effect, String rule, boolean optional) {
|
||||
super(worksInZone, effect, optional);
|
||||
this.fromZone = fromZone;
|
||||
this.toZone = toZone;
|
||||
this.rule = rule;
|
||||
}
|
||||
|
||||
|
||||
public ZoneChangeTriggeredAbility(Zone toZone, Effect effect, String rule, boolean optional) {
|
||||
super(toZone, effect, optional);
|
||||
this.fromZone = null;
|
||||
|
|
@ -62,7 +66,7 @@ public class ZoneChangeTriggeredAbility extends TriggeredAbilityImpl {
|
|||
this.rule = rule;
|
||||
}
|
||||
|
||||
public ZoneChangeTriggeredAbility(ZoneChangeTriggeredAbility ability) {
|
||||
public ZoneChangeTriggeredAbility(final ZoneChangeTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.fromZone = ability.fromZone;
|
||||
this.toZone = ability.toZone;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
|
|
@ -62,8 +63,9 @@ public class CastSourceTriggeredAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getType().equals(GameEvent.EventType.SPELL_CAST) && event.getSourceId().equals(this.getSourceId())) {
|
||||
if (getSourceObject() != null && getSourceObject() instanceof Spell) {
|
||||
Spell spell = (Spell)getSourceObject();
|
||||
MageObject sourceObject = getSourceObject(game);
|
||||
if (sourceObject != null && (sourceObject instanceof Spell)) {
|
||||
Spell spell = (Spell)sourceObject;
|
||||
if (spell.getSpellAbility() != null) {
|
||||
for (Effect effect : getEffects()) {
|
||||
effect.setValue(SOURCE_CAST_SPELL_ABILITY, spell.getSpellAbility());
|
||||
|
|
|
|||
|
|
@ -29,15 +29,19 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -45,12 +49,6 @@ import mage.players.Player;
|
|||
*/
|
||||
public class ExileTargetForSourceEffect extends OneShotEffect {
|
||||
|
||||
private String exileZone = null;
|
||||
|
||||
public ExileTargetForSourceEffect(String exileZone) {
|
||||
this();
|
||||
this.exileZone = exileZone;
|
||||
}
|
||||
|
||||
public ExileTargetForSourceEffect() {
|
||||
super(Outcome.Exile);
|
||||
|
|
@ -58,7 +56,6 @@ public class ExileTargetForSourceEffect extends OneShotEffect {
|
|||
|
||||
public ExileTargetForSourceEffect(final ExileTargetForSourceEffect effect) {
|
||||
super(effect);
|
||||
this.exileZone = effect.exileZone;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -69,15 +66,16 @@ public class ExileTargetForSourceEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source));
|
||||
UUID exileId = source.getSourceId();
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (controller != null && sourceObject != null) {
|
||||
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||
UUID exileId = CardUtil.getObjectExileZoneId(game, sourceObject);
|
||||
if (permanent != null) {
|
||||
return controller.moveCardToExileWithInfo(permanent, exileId, exileZone, source.getSourceId(), game, Zone.BATTLEFIELD);
|
||||
return controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getLogName(), source.getSourceId(), game, Zone.BATTLEFIELD);
|
||||
} else {
|
||||
Card card = game.getCard(targetPointer.getFirst(game, source));
|
||||
Card card = game.getCard(getTargetPointer().getFirst(game, source));
|
||||
if (card != null) {
|
||||
return controller.moveCardToExileWithInfo(card, exileId, exileZone, source.getSourceId(), game, game.getState().getZone(card.getId()));
|
||||
return controller.moveCardToExileWithInfo(card, exileId, sourceObject.getLogName(), source.getSourceId(), game, game.getState().getZone(card.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,9 +30,12 @@ package mage.abilities.effects.common;
|
|||
|
||||
import java.util.LinkedList;
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import static mage.constants.Zone.BATTLEFIELD;
|
||||
|
|
@ -41,6 +44,7 @@ import static mage.constants.Zone.HAND;
|
|||
import mage.game.ExileZone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -75,9 +79,10 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
UUID exileId = source.getSourceId();
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (controller != null && sourceObject != null) {
|
||||
UUID exileId = CardUtil.getObjectExileZoneId(game, sourceObject);
|
||||
ExileZone exile = game.getExile().getExileZone(exileId);
|
||||
if (exile != null) { // null is valid if source left battlefield before enters the battlefield effect resolved
|
||||
LinkedList<UUID> cards = new LinkedList<>(exile);
|
||||
|
|
@ -86,7 +91,7 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect {
|
|||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
game.informPlayers(controller.getName() + " moves " + card.getLogName() + " to " + zone.toString().toLowerCase());
|
||||
game.informPlayers(controller.getName() + " moves " + card.getLogName() + " from exile to " + zone.toString().toLowerCase());
|
||||
card.moveToZone(zone, source.getSourceId(), game, tapped);
|
||||
}
|
||||
exile.clear();
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -35,6 +37,7 @@ import mage.abilities.effects.OneShotEffect;
|
|||
import mage.cards.Card;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -42,13 +45,25 @@ import mage.players.Player;
|
|||
*/
|
||||
public class ReturnToBattlefieldUnderYourControlTargetEffect extends OneShotEffect {
|
||||
|
||||
private boolean fromExileZone;
|
||||
|
||||
public ReturnToBattlefieldUnderYourControlTargetEffect() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param fromExileZone - the card will only be retunred if it's still in the sour obect specific exile zone
|
||||
*/
|
||||
public ReturnToBattlefieldUnderYourControlTargetEffect(boolean fromExileZone) {
|
||||
super(Outcome.Benefit);
|
||||
staticText = "return that card to the battlefield under your control";
|
||||
this.fromExileZone = fromExileZone;
|
||||
}
|
||||
|
||||
public ReturnToBattlefieldUnderYourControlTargetEffect(final ReturnToBattlefieldUnderYourControlTargetEffect effect) {
|
||||
super(effect);
|
||||
this.fromExileZone = effect.fromExileZone;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -59,17 +74,23 @@ public class ReturnToBattlefieldUnderYourControlTargetEffect extends OneShotEffe
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Card card = game.getCard(targetPointer.getFirst(game, source));
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (controller != null && sourceObject != null) {
|
||||
Card card = null;
|
||||
if (fromExileZone) {
|
||||
UUID exilZoneId = CardUtil.getObjectExileZoneId(game, sourceObject);
|
||||
if (exilZoneId != null) {
|
||||
card = game.getExile().getExileZone(exilZoneId).get(getTargetPointer().getFirst(game, source), game);
|
||||
}
|
||||
} else {
|
||||
card = game.getCard(targetPointer.getFirst(game, source));
|
||||
}
|
||||
if (card != null) {
|
||||
Zone currentZone = game.getState().getZone(card.getId());
|
||||
if (controller.putOntoBattlefieldWithInfo(card, game, currentZone, source.getSourceId())) {
|
||||
return true;
|
||||
}
|
||||
controller.putOntoBattlefieldWithInfo(card, game, currentZone, source.getSourceId());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ import mage.game.Game;
|
|||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetControlledPermanent;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/*
|
||||
* @author LevelX2
|
||||
|
|
@ -151,14 +152,16 @@ class ChampionExileCost extends CostImpl {
|
|||
@Override
|
||||
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
|
||||
Player controller = game.getPlayer(controllerId);
|
||||
if (controller != null) {
|
||||
MageObject sourceObject = ability.getSourceObject(game);
|
||||
if (controller != null && sourceObject != null) {
|
||||
if (targets.choose(Outcome.Exile, controllerId, sourceId, game)) {
|
||||
UUID exileId = CardUtil.getObjectExileZoneId(game, sourceObject);
|
||||
for (UUID targetId: targets.get(0).getTargets()) {
|
||||
Permanent permanent = game.getPermanent(targetId);
|
||||
if (permanent == null) {
|
||||
return false;
|
||||
}
|
||||
paid |= controller.moveCardToExileWithInfo(permanent, sourceId, exileZone, sourceId, game, Zone.BATTLEFIELD);
|
||||
paid |= controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getLogName() + " championed permanents", sourceId, game, Zone.BATTLEFIELD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -476,5 +476,15 @@ public class StackAbility implements StackObject, Ability {
|
|||
this.ability.setWorksFaceDown(worksFaceDown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MageObject getSourceObject(Game game) {
|
||||
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceObject(MageObject sourceObject) {
|
||||
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ public class CardUtil {
|
|||
private static final String regexGreen = ".*\\x7b.{0,2}G.{0,2}\\x7d.*";
|
||||
private static final String regexWhite = ".*\\x7b.{0,2}W.{0,2}\\x7d.*";
|
||||
|
||||
private static final String SOURCE_EXILE_ZONE_TEXT = "SourceExileZone";
|
||||
|
||||
static String numberStrings[] = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
|
||||
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "ninteen", "twenty"};
|
||||
|
||||
|
|
@ -483,13 +485,28 @@ public class CardUtil {
|
|||
}
|
||||
|
||||
public static UUID getCardExileZoneId(Game game, UUID sourceId, boolean previous) {
|
||||
String key = getCardZoneString("SourceExileZone", sourceId, game, previous);
|
||||
return getExileZoneId(getCardZoneString(SOURCE_EXILE_ZONE_TEXT, sourceId, game, previous), game);
|
||||
}
|
||||
|
||||
public static UUID getObjectExileZoneId(Game game, MageObject mageObject) {
|
||||
int zoneChangeCounter = 0;
|
||||
if (mageObject instanceof Card) {
|
||||
zoneChangeCounter = ((Card) mageObject).getZoneChangeCounter();
|
||||
}
|
||||
return getExileZoneId(getObjectZoneString(SOURCE_EXILE_ZONE_TEXT,mageObject.getId(), game, zoneChangeCounter, false), game);
|
||||
}
|
||||
|
||||
public static UUID getExileZoneId(Game game, UUID objectId, int zoneChangeCounter) {
|
||||
return getExileZoneId(getObjectZoneString(SOURCE_EXILE_ZONE_TEXT,objectId, game, zoneChangeCounter, false), game);
|
||||
}
|
||||
|
||||
public static UUID getExileZoneId(String key, Game game) {
|
||||
UUID exileId = (UUID) game.getState().getValue(key);
|
||||
if (exileId == null) {
|
||||
exileId = UUID.randomUUID();
|
||||
game.getState().setValue(key, exileId);
|
||||
}
|
||||
return exileId;
|
||||
return exileId;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -506,18 +523,23 @@ public class CardUtil {
|
|||
return getCardZoneString(text, cardId, game, false);
|
||||
}
|
||||
|
||||
public static String getCardZoneString(String text, UUID cardId, Game game, boolean previous) {
|
||||
|
||||
public static String getCardZoneString(String text, UUID cardId, Game game, boolean previous) {
|
||||
int zoneChangeCounter= 0;
|
||||
Card card = game.getCard(cardId); // if called for a token, the id is enough
|
||||
if (card != null) {
|
||||
zoneChangeCounter = card.getZoneChangeCounter();
|
||||
}
|
||||
return getObjectZoneString(text,cardId, game, zoneChangeCounter, previous);
|
||||
}
|
||||
|
||||
public static String getObjectZoneString(String text, UUID objectId, Game game, int zoneChangeCounter, boolean previous) {
|
||||
StringBuilder uniqueString = new StringBuilder();
|
||||
if (text != null) {
|
||||
uniqueString.append(text);
|
||||
}
|
||||
uniqueString.append(cardId);
|
||||
Card card = game.getCard(cardId); // if called for a token, the id is enough
|
||||
if (card != null) {
|
||||
uniqueString.append(previous ? card.getZoneChangeCounter() - 1: card.getZoneChangeCounter());
|
||||
}
|
||||
return uniqueString.toString();
|
||||
uniqueString.append(objectId);
|
||||
uniqueString.append(previous ? zoneChangeCounter - 1: zoneChangeCounter);
|
||||
return uniqueString.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue