mirror of
https://github.com/magefree/mage.git
synced 2025-12-25 21:12:04 -08:00
Merge branch 'master' into Network_Upgrade
Conflicts: Mage.Client/src/main/java/mage/client/chat/ChatPanel.java Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java Mage.Client/src/main/java/mage/client/table/TablesPanel.java Mage.Common/src/mage/remote/SessionImpl.java Mage.Server/src/main/java/mage/server/Session.java
This commit is contained in:
commit
f4aff4a121
894 changed files with 23817 additions and 4981 deletions
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-root</artifactId>
|
||||
<version>1.4.0</version>
|
||||
<version>1.4.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mage</artifactId>
|
||||
|
|
|
|||
|
|
@ -69,7 +69,11 @@ public class MageObjectReference implements Comparable<MageObjectReference>, Ser
|
|||
if (mageObject != null) {
|
||||
this.zoneChangeCounter = mageObject.getZoneChangeCounter(game);
|
||||
} else {
|
||||
throw new IllegalArgumentException("The provided sourceId is not connected to an object in the game");
|
||||
if (game.getPlayerList().contains(sourceId)) {
|
||||
this.zoneChangeCounter = 0;
|
||||
} else {
|
||||
throw new IllegalArgumentException("The provided sourceId is not connected to an object in the game");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
return false;
|
||||
}
|
||||
game.applyEffects();
|
||||
|
||||
|
||||
/* 20130201 - 601.2b
|
||||
* If the spell is modal the player announces the mode choice (see rule 700.2).
|
||||
*/
|
||||
|
|
@ -299,7 +299,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
// A player can't apply two alternative methods of casting or two alternative costs to a single spell.
|
||||
if (!activateAlternateOrAdditionalCosts(sourceObject, noMana, controller, game)){
|
||||
if (getAbilityType().equals(AbilityType.SPELL)
|
||||
&& ((SpellAbility) this).getSpellAbilityType().equals(SpellAbilityType.LAND_ALTERNATE)) {
|
||||
&& ((SpellAbility) this).getSpellAbilityType().equals(SpellAbilityType.FACE_DOWN_CREATURE)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -329,7 +329,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
// and/or zones become the target of a spell trigger at this point; they'll wait to be put on
|
||||
// the stack until the spell has finished being cast.)
|
||||
|
||||
if (sourceObject != null && !this.getAbilityType().equals(AbilityType.TRIGGERED)) { // triggered abilities check this already TriggeredAbilities.checkTriggers()
|
||||
if (sourceObject != null && !this.getAbilityType().equals(AbilityType.TRIGGERED)) { // triggered abilities check this already in playerImpl.triggerAbility
|
||||
sourceObject.adjustTargets(this, game);
|
||||
}
|
||||
if (getTargets().size() > 0 && getTargets().chooseTargets(getEffects().get(0).getOutcome(), this.controllerId, this, game) == false) {
|
||||
|
|
|
|||
|
|
@ -79,10 +79,10 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
}
|
||||
|
||||
// TODO: Implement for all TriggeredAbilities so this default method can be removed
|
||||
@Override
|
||||
/*@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return true;
|
||||
}
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public boolean resolve(Game game) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.effects.common.combat.AttacksIfAbleSourceEffect;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Zone;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class AttacksEachCombatStaticAbility extends StaticAbility {
|
||||
|
||||
public AttacksEachCombatStaticAbility() {
|
||||
super(Zone.BATTLEFIELD, new AttacksIfAbleSourceEffect(Duration.WhileOnBattlefield, true));
|
||||
}
|
||||
|
||||
public AttacksEachCombatStaticAbility(AttacksEachCombatStaticAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttacksEachCombatStaticAbility copy() {
|
||||
return new AttacksEachCombatStaticAbility(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@ import mage.constants.Duration;
|
|||
import mage.constants.Zone;
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.effects.common.combat.AttacksIfAbleSourceEffect;
|
||||
import mage.watchers.common.AttackedThisTurnWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -41,6 +42,7 @@ public class AttacksEachTurnStaticAbility extends StaticAbility {
|
|||
|
||||
public AttacksEachTurnStaticAbility() {
|
||||
super(Zone.BATTLEFIELD, new AttacksIfAbleSourceEffect(Duration.WhileOnBattlefield));
|
||||
addWatcher(new AttackedThisTurnWatcher());
|
||||
}
|
||||
|
||||
public AttacksEachTurnStaticAbility(AttacksEachTurnStaticAbility ability) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class EndOfCombatTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public EndOfCombatTriggeredAbility(Effect effect, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
}
|
||||
|
||||
public EndOfCombatTriggeredAbility(final EndOfCombatTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EndOfCombatTriggeredAbility copy() {
|
||||
return new EndOfCombatTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.END_COMBAT_STEP_PRE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "At the end of combat, " + super.getRule();
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import java.util.UUID;
|
|||
* @author Loki
|
||||
*/
|
||||
public class CardsInOpponentGraveCondition implements Condition {
|
||||
private int value;
|
||||
private final int value;
|
||||
|
||||
public CardsInOpponentGraveCondition(int value) {
|
||||
this.value = value;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public class KickedCondition implements Condition {
|
|||
if (card != null) {
|
||||
for (Ability ability: card.getAbilities()) {
|
||||
if (ability instanceof KickerAbility) {
|
||||
if(((KickerAbility) ability).isKicked(game)) {
|
||||
if(((KickerAbility) ability).isKicked(game, source, "")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,17 +24,9 @@ public class KickedCostCondition implements Condition {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
KickerAbility kickerAbility = null;
|
||||
for (Ability ability: card.getAbilities()) {
|
||||
if (ability instanceof KickerAbility) {
|
||||
kickerAbility = (KickerAbility) ability;
|
||||
}
|
||||
}
|
||||
if (kickerAbility != null) {
|
||||
for (OptionalAdditionalCost cost: kickerAbility.getKickerCosts()) {
|
||||
if (cost.getText(true).equals(kickerCostText)) {
|
||||
return cost.isActivated();
|
||||
}
|
||||
return ((KickerAbility) ability).isKicked(game, source, kickerCostText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,31 +28,29 @@
|
|||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.predicate.permanent.ControllerPredicate;
|
||||
import mage.filter.predicate.permanent.ControllerIdPredicate;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
*
|
||||
* Checks if one opponent (each opponent is checked on its own) fulfills
|
||||
* the defined condition of controlling the defined number of permanents.
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class OpponentControlsPermanentCondition implements Condition {
|
||||
|
||||
public static enum CountType { MORE_THAN, FEWER_THAN, EQUAL_TO };
|
||||
|
||||
private FilterPermanent filter;
|
||||
private Condition condition;
|
||||
private CountType type;
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* Applies a filter and delegates creation to
|
||||
* {@link #ControlsPermanent(mage.filter.FilterPermanent, mage.abilities.condition.common.ControlsPermanent.CountType, int)}
|
||||
* with {@link CountType#MORE_THAN}, and 0.
|
||||
*
|
||||
* @param filter
|
||||
*/
|
||||
public OpponentControlsPermanentCondition(FilterPermanent filter) {
|
||||
|
|
@ -74,46 +72,33 @@ public class OpponentControlsPermanentCondition implements Condition {
|
|||
this.count = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a filter, a {@link CountType}, and count to permanents on the
|
||||
* battlefield and calls the decorated condition to see if it
|
||||
* {@link #apply(mage.game.Game, mage.abilities.Ability) applies}
|
||||
* as well. This will force both conditions to apply for this to be true.
|
||||
*
|
||||
* @param filter
|
||||
* @param type
|
||||
* @param count
|
||||
* @param conditionToDecorate
|
||||
*/
|
||||
public OpponentControlsPermanentCondition ( FilterPermanent filter, CountType type, int count, Condition conditionToDecorate ) {
|
||||
this(filter, type, count);
|
||||
this.condition = conditionToDecorate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
boolean conditionApplies = false;
|
||||
|
||||
FilterPermanent localFilter = filter.copy();
|
||||
localFilter.add(new ControllerPredicate(TargetController.OPPONENT));
|
||||
|
||||
switch ( this.type ) {
|
||||
case FEWER_THAN:
|
||||
conditionApplies = game.getBattlefield().count(localFilter, source.getSourceId(), source.getControllerId(), game) < this.count;
|
||||
break;
|
||||
case MORE_THAN:
|
||||
conditionApplies = game.getBattlefield().count(localFilter, source.getSourceId(), source.getControllerId(), game) > this.count;
|
||||
break;
|
||||
case EQUAL_TO:
|
||||
conditionApplies = game.getBattlefield().count(localFilter, source.getSourceId(), source.getControllerId(), game) == this.count;
|
||||
break;
|
||||
boolean conditionApplies = false;
|
||||
for(UUID opponentId :game.getOpponents(source.getControllerId())) {
|
||||
FilterPermanent localFilter = filter.copy();
|
||||
localFilter.add(new ControllerIdPredicate(opponentId));
|
||||
switch ( this.type ) {
|
||||
case FEWER_THAN:
|
||||
if (game.getBattlefield().count(localFilter, source.getSourceId(), source.getControllerId(), game) < this.count) {
|
||||
conditionApplies = true;
|
||||
break;
|
||||
}
|
||||
case MORE_THAN:
|
||||
if (game.getBattlefield().count(localFilter, source.getSourceId(), source.getControllerId(), game) > this.count) {
|
||||
conditionApplies = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case EQUAL_TO:
|
||||
if (game.getBattlefield().count(localFilter, source.getSourceId(), source.getControllerId(), game) == this.count) {
|
||||
conditionApplies = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//If a decorated condition exists, check it as well and apply them together.
|
||||
if ( this.condition != null ) {
|
||||
conditionApplies = conditionApplies && this.condition.apply(game, source);
|
||||
}
|
||||
|
||||
return conditionApplies;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.game.Game;
|
||||
import mage.watchers.common.DamageDoneWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class SourceDealtDamageCondition implements Condition {
|
||||
private final int value;
|
||||
|
||||
public SourceDealtDamageCondition(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
DamageDoneWatcher watcher = (DamageDoneWatcher) game.getState().getWatchers().get("DamageDone");
|
||||
return watcher != null && watcher.damageDone(source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game) >= value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{this} has dealt " + value + " or more damage this turn" ;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.constants.CardType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class SpellMasteryCondition implements Condition {
|
||||
|
||||
private static final FilterCard filter = new FilterCard();
|
||||
|
||||
static {
|
||||
filter.add(Predicates.or(new CardTypePredicate(CardType.INSTANT), new CardTypePredicate(CardType.SORCERY)));
|
||||
}
|
||||
|
||||
private static SpellMasteryCondition fInstance = null;
|
||||
|
||||
public static SpellMasteryCondition getInstance() {
|
||||
if (fInstance == null) {
|
||||
fInstance = new SpellMasteryCondition();
|
||||
}
|
||||
return fInstance;
|
||||
}
|
||||
|
||||
private SpellMasteryCondition() {}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
return player != null && player.getGraveyard().count(filter, game) >= 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "there are two or more instant and/or sorcery cards in your graveyard";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package mage.abilities.decorator;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.condition.Condition;
|
||||
|
|
@ -74,4 +75,21 @@ public class ConditionalTriggeredAbility extends TriggeredAbilityImpl {
|
|||
return ability.getEffects();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MageObject getSourceObjectIfItStillExists(Game game) {
|
||||
return ability.getSourceObjectIfItStillExists(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MageObject getSourceObject(Game game) {
|
||||
return ability.getSourceObject(game);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public int getSourceObjectZoneChangeCounter() {
|
||||
return ability.getSourceObjectZoneChangeCounter();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
package mage.abilities.dynamicvalue.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author cbrianhill
|
||||
*/
|
||||
public class CardsInTargetPlayerHandCount implements DynamicValue {
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
Player player = game.getPlayer(effect.getTargetPointer().getFirst(game, sourceAbility));
|
||||
if (player != null) {
|
||||
return player.getHand().size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicValue copy() {
|
||||
return new CardsInTargetPlayerHandCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "cards in target player's hand";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ public class MultikickerCount implements DynamicValue {
|
|||
if (card != null) {
|
||||
for (Ability ability: card.getAbilities()) {
|
||||
if (ability instanceof KickerAbility) {
|
||||
count += ((KickerAbility) ability).getKickedCounter(game);
|
||||
count += ((KickerAbility) ability).getKickedCounter(game, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,4 +61,7 @@ public interface ContinuousEffect extends Effect {
|
|||
void newId();
|
||||
@Override
|
||||
ContinuousEffect copy();
|
||||
|
||||
boolean isTemporary();
|
||||
void setTemporary(boolean temporary);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,8 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
protected boolean discarded = false; // for manual effect discard
|
||||
protected boolean affectedObjectsSet = false;
|
||||
protected List<MageObjectReference> affectedObjectList = new ArrayList<>();
|
||||
|
||||
protected boolean temporary = false;
|
||||
|
||||
// until your next turn
|
||||
protected int startingTurn;
|
||||
protected UUID startingControllerId;
|
||||
|
|
@ -96,6 +97,7 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
this.discarded = effect.discarded;
|
||||
this.affectedObjectsSet = effect.affectedObjectsSet;
|
||||
this.affectedObjectList.addAll(effect.affectedObjectList);
|
||||
this.temporary = effect.temporary;
|
||||
this.startingTurn = effect.startingTurn;
|
||||
this.startingControllerId = effect.startingControllerId;
|
||||
}
|
||||
|
|
@ -234,4 +236,18 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
return affectedObjectList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status if the effect is temporary added to the ContinuousEffects
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean isTemporary() {
|
||||
return temporary;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTemporary(boolean temporary) {
|
||||
this.temporary = temporary;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -939,6 +939,7 @@ public class ContinuousEffects implements Serializable {
|
|||
*/
|
||||
public void addEffect(ContinuousEffect effect, UUID sourceId, Ability source) {
|
||||
if (!(source instanceof MageSingleton)) { // because MageSingletons may never be removed by removing the temporary effecs they are not added to the temporaryEffects to prevent this
|
||||
effect.setTemporary(true);
|
||||
Set abilities = temporaryEffects.get(effect);
|
||||
if (abilities == null) {
|
||||
abilities = new HashSet<>();
|
||||
|
|
|
|||
|
|
@ -95,21 +95,14 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (event.getType() == EventType.ENTERS_THE_BATTLEFIELD) {
|
||||
if (event.getTargetId().equals(source.getSourceId())) {
|
||||
if (condition == null || condition.apply(game, source)) {
|
||||
return true;
|
||||
}
|
||||
if (event.getTargetId().equals(source.getSourceId())) {
|
||||
if (condition == null || condition.apply(game, source)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
if (optional) {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import mage.constants.Outcome;
|
|||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -64,10 +65,10 @@ public class ChooseColorEffect extends OneShotEffect {
|
|||
}
|
||||
}
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(new StringBuilder(permanent.getLogName()).append(": ").append(controller.getLogName()).append(" has chosen ").append(choice.getChoice()).toString());
|
||||
game.informPlayers(permanent.getLogName()+": "+controller.getLogName()+" has chosen "+choice.getChoice());
|
||||
}
|
||||
game.getState().setValue(source.getSourceId() + "_color", choice.getColor());
|
||||
permanent.addInfo("chosen color", "<font color = 'blue'>Chosen color: " + choice.getColor().getDescription() + "</font>", game);
|
||||
permanent.addInfo("chosen color", CardUtil.addToolTipMarkTags("Chosen color: " + choice.getChoice()), game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import mage.constants.Duration;
|
|||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
|
|
@ -56,6 +57,7 @@ public class CopyEffect extends ContinuousEffectImpl {
|
|||
* Object we copy from
|
||||
*/
|
||||
private MageObject target;
|
||||
|
||||
private UUID sourceId;
|
||||
private ApplyToPermanent applier;
|
||||
|
||||
|
|
@ -65,7 +67,7 @@ public class CopyEffect extends ContinuousEffectImpl {
|
|||
|
||||
public CopyEffect(Duration duration, MageObject target, UUID sourceId) {
|
||||
super(duration, Layer.CopyEffects_1, SubLayer.NA, Outcome.BecomeCreature);
|
||||
this.target = target;
|
||||
this.target = target;
|
||||
this.sourceId = sourceId;
|
||||
}
|
||||
|
||||
|
|
@ -79,23 +81,24 @@ public class CopyEffect extends ContinuousEffectImpl {
|
|||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
super.init(source, game);
|
||||
if (affectedObjectsSet) {
|
||||
affectedObjectList.add(new MageObjectReference(sourceId, game));
|
||||
if (!(target instanceof Permanent) && (target instanceof Card)) {
|
||||
this.target = new PermanentCard((Card)target, source.getControllerId(), game);
|
||||
}
|
||||
affectedObjectList.add(new MageObjectReference(getSourceId(), game));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent;
|
||||
if (affectedObjectsSet) {
|
||||
permanent = affectedObjectList.get(0).getPermanent(game);
|
||||
} else {
|
||||
permanent = game.getPermanent(this.sourceId);
|
||||
}
|
||||
Permanent permanent = affectedObjectList.get(0).getPermanent(game);
|
||||
if (permanent == null) {
|
||||
discard();
|
||||
return false;
|
||||
permanent = (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD, source.getSourceObjectZoneChangeCounter());
|
||||
// As long as the permanent is still in the LKI continue to copy to get triggered abilities to TriggeredAbilites for dies events.
|
||||
if (permanent == null) {
|
||||
discard();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
permanent.setCopy(true);
|
||||
permanent.setName(target.getName());
|
||||
permanent.getColor(game).setColor(target.getColor(game));
|
||||
permanent.getManaCost().clear();
|
||||
|
|
@ -134,9 +137,7 @@ public class CopyEffect extends ContinuousEffectImpl {
|
|||
} else if (target instanceof PermanentToken || target instanceof Card) {
|
||||
permanent.setCardNumber(((Card) target).getCardNumber());
|
||||
permanent.setExpansionSetCode(((Card) target).getExpansionSetCode());
|
||||
}
|
||||
|
||||
permanent.setCopy(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,8 +69,9 @@ public class CopyTargetSpellEffect extends OneShotEffect {
|
|||
if (activateMessage.startsWith(" casts ")) {
|
||||
activateMessage = activateMessage.substring(6);
|
||||
}
|
||||
if (!game.isSimulation())
|
||||
game.informPlayers(player.getLogName() + " copies " + activateMessage);
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(player.getLogName() + activateMessage);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.keyword.TransformAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class ExileAndReturnTransformedSourceEffect extends OneShotEffect {
|
||||
|
||||
public static enum Gender { MALE, FEMAL };
|
||||
|
||||
public ExileAndReturnTransformedSourceEffect(Gender gender) {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "exile {this}, then return " + (gender.equals(Gender.MALE) ? "him":"her")
|
||||
+ " to the battlefield transformed under" + (gender.equals(Gender.MALE) ? "his":"her")+ " owner's control";
|
||||
}
|
||||
|
||||
public ExileAndReturnTransformedSourceEffect(final ExileAndReturnTransformedSourceEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExileAndReturnTransformedSourceEffect copy() {
|
||||
return new ExileAndReturnTransformedSourceEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
MageObject sourceObject = source.getSourceObjectIfItStillExists(game);
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (sourceObject != null && controller != null) {
|
||||
Card card = (Card) sourceObject;
|
||||
if (controller.moveCards(card, Zone.BATTLEFIELD, Zone.EXILED, source, game)) {
|
||||
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE);
|
||||
controller.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -35,6 +35,7 @@ import mage.cards.Card;
|
|||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
|
|
@ -58,12 +59,15 @@ public class ShuffleSpellEffect extends OneShotEffect implements MageSingleton {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Card spellCard = game.getStack().getSpell(source.getSourceId()).getCard();
|
||||
if (spellCard != null) {
|
||||
Player owner = game.getPlayer(spellCard.getOwnerId());
|
||||
if (owner != null) {
|
||||
controller.moveCardToLibraryWithInfo(spellCard, source.getSourceId(), game, Zone.STACK, true, true);
|
||||
owner.shuffleLibrary(game);
|
||||
Spell spell = game.getStack().getSpell(source.getSourceId());
|
||||
if (spell != null) {
|
||||
Card spellCard = spell.getCard();
|
||||
if (spellCard != null) {
|
||||
Player owner = game.getPlayer(spellCard.getOwnerId());
|
||||
if (owner != null) {
|
||||
controller.moveCardToLibraryWithInfo(spellCard, source.getSourceId(), game, Zone.STACK, true, true);
|
||||
owner.shuffleLibrary(game);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import mage.abilities.Ability;
|
|||
import mage.abilities.effects.RequirementEffect;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.watchers.common.AttackedThisTurnWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -40,18 +41,25 @@ import mage.game.permanent.Permanent;
|
|||
*/
|
||||
public class AttacksIfAbleSourceEffect extends RequirementEffect {
|
||||
|
||||
boolean eachCombat;
|
||||
|
||||
public AttacksIfAbleSourceEffect(Duration duration) {
|
||||
this(duration, false);
|
||||
}
|
||||
|
||||
public AttacksIfAbleSourceEffect(Duration duration, boolean eachCombat) {
|
||||
super(duration);
|
||||
this.eachCombat = eachCombat;
|
||||
if (this.duration == Duration.EndOfTurn) {
|
||||
staticText = "{this} attacks this turn if able";
|
||||
}
|
||||
else {
|
||||
staticText = "{this} attacks each turn if able";
|
||||
staticText = "{this} attacks " + (eachCombat ? "each combat" :"this turn") + " if able";
|
||||
} else {
|
||||
staticText = "{this} attacks each " + (eachCombat ? "combat" :"turn") + " if able";
|
||||
}
|
||||
}
|
||||
|
||||
public AttacksIfAbleSourceEffect(final AttacksIfAbleSourceEffect effect) {
|
||||
super(effect);
|
||||
this.eachCombat = effect.eachCombat;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -61,7 +69,14 @@ public class AttacksIfAbleSourceEffect extends RequirementEffect {
|
|||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
return permanent.getId().equals(source.getSourceId());
|
||||
if (permanent.getId().equals(source.getSourceId())) {
|
||||
if (eachCombat) {
|
||||
return true;
|
||||
}
|
||||
AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher)game.getState().getWatchers().get("AttackedThisTurn");
|
||||
return watcher != null && !watcher.getAttackedThisTurnCreatures().contains(permanent.getId());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ public class BecomesBasicLandTargetEffect extends ContinuousEffectImpl {
|
|||
|
||||
protected boolean chooseLandType;
|
||||
protected ArrayList<String> landTypes = new ArrayList();
|
||||
protected boolean loseOther; // loses all other abilities, card types, and creature types
|
||||
|
||||
public BecomesBasicLandTargetEffect(Duration duration) {
|
||||
this(duration, true, new String[0]);
|
||||
|
|
@ -69,10 +70,15 @@ public class BecomesBasicLandTargetEffect extends ContinuousEffectImpl {
|
|||
}
|
||||
|
||||
public BecomesBasicLandTargetEffect(Duration duration, boolean chooseLandType, String... landNames) {
|
||||
this(duration, chooseLandType, true, landNames);
|
||||
}
|
||||
|
||||
public BecomesBasicLandTargetEffect(Duration duration, boolean chooseLandType, boolean loseOther, String... landNames) {
|
||||
super(duration, Outcome.Detriment);
|
||||
this.landTypes.addAll(Arrays.asList(landNames));
|
||||
this.chooseLandType = chooseLandType;
|
||||
this.staticText = setText();
|
||||
this.loseOther = loseOther;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -105,6 +111,19 @@ public class BecomesBasicLandTargetEffect extends ContinuousEffectImpl {
|
|||
this.discard();
|
||||
}
|
||||
}
|
||||
|
||||
if(!loseOther) {
|
||||
for (UUID targetPermanent : targetPointer.getTargets(game, source)) {
|
||||
Permanent land = game.getPermanent(targetPermanent);
|
||||
if (land != null) {
|
||||
for(String type : land.getSubtype()) {
|
||||
if(!landTypes.contains(type)) {
|
||||
landTypes.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -116,16 +135,22 @@ public class BecomesBasicLandTargetEffect extends ContinuousEffectImpl {
|
|||
case AbilityAddingRemovingEffects_6:
|
||||
land.removeAllAbilities(source.getSourceId(), game);
|
||||
for (String landType : landTypes) {
|
||||
if (landType.equals("Swamp")) {
|
||||
land.addAbility(new BlackManaAbility(), source.getSourceId(), game);
|
||||
} else if (landType.equals("Mountain")) {
|
||||
land.addAbility(new RedManaAbility(), source.getSourceId(), game);
|
||||
} else if (landType.equals("Forest")) {
|
||||
land.addAbility(new GreenManaAbility(), source.getSourceId(), game);
|
||||
} else if (landType.equals("Island")) {
|
||||
land.addAbility(new BlueManaAbility(), source.getSourceId(), game);
|
||||
} else if (landType.equals("Plains")) {
|
||||
land.addAbility(new WhiteManaAbility(), source.getSourceId(), game);
|
||||
switch (landType) {
|
||||
case "Swamp":
|
||||
land.addAbility(new BlackManaAbility(), source.getSourceId(), game);
|
||||
break;
|
||||
case "Mountain":
|
||||
land.addAbility(new RedManaAbility(), source.getSourceId(), game);
|
||||
break;
|
||||
case "Forest":
|
||||
land.addAbility(new GreenManaAbility(), source.getSourceId(), game);
|
||||
break;
|
||||
case "Island":
|
||||
land.addAbility(new BlueManaAbility(), source.getSourceId(), game);
|
||||
break;
|
||||
case "Plains":
|
||||
land.addAbility(new WhiteManaAbility(), source.getSourceId(), game);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ public class GainAbilityAllEffect extends ContinuousEffectImpl {
|
|||
public GainAbilityAllEffect(final GainAbilityAllEffect effect) {
|
||||
super(effect);
|
||||
this.ability = effect.ability.copy();
|
||||
ability.newId(); // This is needed if the effect is copied e.g. by a clone so the ability can be added multiple times to permanents
|
||||
this.filter = effect.filter.copy();
|
||||
this.excludeSource = effect.excludeSource;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ public class GainAbilityAttachedEffect extends ContinuousEffectImpl {
|
|||
public GainAbilityAttachedEffect(final GainAbilityAttachedEffect effect) {
|
||||
super(effect);
|
||||
this.ability = effect.ability.copy();
|
||||
ability.newId(); // This is needed if the effect is copied e.g. by a clone so the ability can be added multiple times to permanents
|
||||
this.attachmentType = effect.attachmentType;
|
||||
this.fixedTarget = effect.fixedTarget;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ public class GainAbilityPairedEffect extends ContinuousEffectImpl {
|
|||
public GainAbilityPairedEffect(final GainAbilityPairedEffect effect) {
|
||||
super(effect);
|
||||
this.ability = effect.ability.copy();
|
||||
ability.newId(); // This is needed if the effect is copied e.g. by a clone so the ability can be added multiple times to permanents
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -68,7 +69,7 @@ public class GainAbilityPairedEffect extends ContinuousEffectImpl {
|
|||
Permanent paired = game.getPermanent(permanent.getPairedCard());
|
||||
if (paired != null) {
|
||||
permanent.addAbility(ability, game);
|
||||
paired.addAbility(ability, source.getSourceId(), game);
|
||||
paired.addAbility(ability, source.getSourceId(), game, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ public class GainAbilitySourceEffect extends ContinuousEffectImpl implements Sou
|
|||
public GainAbilitySourceEffect(final GainAbilitySourceEffect effect) {
|
||||
super(effect);
|
||||
this.ability = effect.ability.copy();
|
||||
ability.newId(); // This is needed if the effect is copied e.g. by a clone so the ability can be added multiple times to permanents
|
||||
this.onCard = effect.onCard;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ public class GainAbilityTargetEffect extends ContinuousEffectImpl {
|
|||
public GainAbilityTargetEffect(final GainAbilityTargetEffect effect) {
|
||||
super(effect);
|
||||
this.ability = effect.ability.copy();
|
||||
ability.newId(); // This is needed if the effect is copied e.g. by a clone so the ability can be added multiple times to permanents
|
||||
this.onCard = effect.onCard;
|
||||
this.durationPhaseStep = effect.durationPhaseStep;
|
||||
this.durationPlayerId = effect.durationPlayerId;
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ import mage.constants.Duration;
|
|||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -76,12 +76,16 @@ public class SetPowerToughnessSourceEffect extends ContinuousEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
MageObject mageObject = game.getObject(source.getSourceId());
|
||||
MageObject mageObject = game.getObject(source.getSourceId());
|
||||
if (mageObject == null) {
|
||||
if (duration.equals(Duration.Custom)) {
|
||||
discard();
|
||||
}
|
||||
return false;
|
||||
} else if (isTemporary()) { // it's somehow w
|
||||
if (!(mageObject instanceof Permanent)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (amount != null) {
|
||||
int value = amount.calculate(game, source, this);
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ public class ProliferateEffect extends OneShotEffect {
|
|||
choices.add(counter.getName());
|
||||
}
|
||||
choice.setChoices(choices);
|
||||
choice.setMessage("Choose a counter to proliferate (" + permanent.getName() + ")");
|
||||
choice.setMessage("Choose a counter to proliferate (" + permanent.getIdName() + ")");
|
||||
controller.choose(Outcome.Benefit, choice, game);
|
||||
for (Counter counter : permanent.getCounters().values()) {
|
||||
if (counter.getName().equals(choice.getChoice())) {
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ import mage.target.common.TargetCardInLibrary;
|
|||
*/
|
||||
public class SearchLibraryPutInPlayEffect extends SearchEffect {
|
||||
|
||||
private boolean tapped;
|
||||
private boolean forceShuffle;
|
||||
protected boolean tapped;
|
||||
protected boolean forceShuffle;
|
||||
|
||||
public SearchLibraryPutInPlayEffect(TargetCardInLibrary target) {
|
||||
this(target, false, true, Outcome.PutCardInPlay);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.effects.common.search;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.SearchEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInLibrary;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class SearchLibraryPutInPlayTargetPlayerEffect extends SearchEffect {
|
||||
|
||||
protected boolean tapped;
|
||||
protected boolean forceShuffle;
|
||||
|
||||
public SearchLibraryPutInPlayTargetPlayerEffect(TargetCardInLibrary target) {
|
||||
this(target, false, true, Outcome.PutCardInPlay);
|
||||
}
|
||||
|
||||
public SearchLibraryPutInPlayTargetPlayerEffect(TargetCardInLibrary target, boolean tapped) {
|
||||
this(target, tapped, true, Outcome.PutCardInPlay);
|
||||
}
|
||||
|
||||
public SearchLibraryPutInPlayTargetPlayerEffect(TargetCardInLibrary target, boolean tapped, boolean forceShuffle) {
|
||||
this(target, tapped, forceShuffle, Outcome.PutCardInPlay);
|
||||
}
|
||||
|
||||
public SearchLibraryPutInPlayTargetPlayerEffect(TargetCardInLibrary target, boolean tapped, Outcome outcome) {
|
||||
this(target, tapped, true, outcome);
|
||||
}
|
||||
|
||||
public SearchLibraryPutInPlayTargetPlayerEffect(TargetCardInLibrary target, boolean tapped, boolean forceShuffle, Outcome outcome) {
|
||||
super(target, outcome);
|
||||
this.tapped = tapped;
|
||||
this.forceShuffle = forceShuffle;
|
||||
setText();
|
||||
}
|
||||
|
||||
public SearchLibraryPutInPlayTargetPlayerEffect(final SearchLibraryPutInPlayTargetPlayerEffect effect) {
|
||||
super(effect);
|
||||
this.tapped = effect.tapped;
|
||||
this.forceShuffle = effect.forceShuffle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchLibraryPutInPlayTargetPlayerEffect copy() {
|
||||
return new SearchLibraryPutInPlayTargetPlayerEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
|
||||
if (player != null) {
|
||||
if (player.searchLibrary(target, game)) {
|
||||
if (target.getTargets().size() > 0) {
|
||||
for (UUID cardId: target.getTargets()) {
|
||||
Card card = player.getLibrary().getCard(cardId, game);
|
||||
if (card != null) {
|
||||
player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId(), tapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
player.shuffleLibrary(game);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (forceShuffle) {
|
||||
player.shuffleLibrary(game);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setText() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("target player searches his or her library for ");
|
||||
if (target.getNumberOfTargets() == 0 && target.getMaxNumberOfTargets() > 0) {
|
||||
if ( target.getMaxNumberOfTargets() == Integer.MAX_VALUE ) {
|
||||
sb.append("any number of ").append(" ");
|
||||
}
|
||||
else {
|
||||
sb.append("up to ").append(target.getMaxNumberOfTargets()).append(" ");
|
||||
}
|
||||
sb.append(target.getTargetName()).append(" and put them onto the battlefield");
|
||||
}
|
||||
else {
|
||||
sb.append("a ").append(target.getTargetName()).append(" and put it onto the battlefield");
|
||||
}
|
||||
if (tapped) {
|
||||
sb.append(" tapped");
|
||||
}
|
||||
if (forceShuffle) {
|
||||
sb.append(". Then that player shuffles his or her library");
|
||||
}
|
||||
else {
|
||||
sb.append(". If that player does, he or she shuffles his or her library");
|
||||
}
|
||||
staticText = sb.toString();
|
||||
}
|
||||
|
||||
public List<UUID> getTargets() {
|
||||
return target.getTargets();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
package mage.abilities.keyword;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ludwig.hirth
|
||||
*/
|
||||
public class CantBlockAloneAttachedEffect {
|
||||
|
||||
}
|
||||
|
|
@ -40,7 +40,6 @@ import mage.constants.Outcome;
|
|||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
|
|
|||
|
|
@ -28,9 +28,11 @@
|
|||
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.StaticAbility;
|
||||
|
|
@ -42,7 +44,7 @@ import mage.abilities.costs.OptionalAdditionalSourceCosts;
|
|||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.costs.mana.VariableManaCost;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
|
|
@ -87,12 +89,12 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
protected static final String KICKER_REMINDER_MANA = "(You may pay an additional {cost} as you cast this spell.)";
|
||||
protected static final String KICKER_REMINDER_COST = "(You may {cost} in addition to any other costs as you cast this spell.)";
|
||||
|
||||
protected Map<String, Integer> activations = new HashMap<>(); // zoneChangeCounter, activations
|
||||
|
||||
protected String keywordText;
|
||||
protected String reminderText;
|
||||
protected List<OptionalAdditionalCost> kickerCosts = new LinkedList<>();
|
||||
private int xManaValue = 0;
|
||||
// needed to reset kicked status, if card changes zone after casting it
|
||||
private int zoneChangeCounter = 0;
|
||||
|
||||
public KickerAbility(String manaString) {
|
||||
this(KICKER_KEYWORD, KICKER_REMINDER_MANA);
|
||||
|
|
@ -118,7 +120,7 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
this.keywordText = ability.keywordText;
|
||||
this.reminderText = ability.reminderText;
|
||||
this.xManaValue = ability.xManaValue;
|
||||
this.zoneChangeCounter = ability.zoneChangeCounter;
|
||||
this.activations.putAll(ability.activations);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -143,35 +145,24 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
for (OptionalAdditionalCost cost: kickerCosts) {
|
||||
cost.reset();
|
||||
}
|
||||
zoneChangeCounter = 0;
|
||||
}
|
||||
|
||||
public int getXManaValue() {
|
||||
return xManaValue;
|
||||
}
|
||||
|
||||
public int getKickedCounter(Game game) {
|
||||
if (isKicked(game)) {
|
||||
int counter = 0;
|
||||
for (OptionalAdditionalCost cost: kickerCosts) {
|
||||
counter += cost.getActivateCount();
|
||||
}
|
||||
return counter;
|
||||
public int getKickedCounter(Game game, Ability source) {
|
||||
String key = getActivationKey(source, "", game);
|
||||
if (activations.containsKey(key)) {
|
||||
return activations.get(key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean isKicked(Game game) {
|
||||
Card card = game.getCard(sourceId);
|
||||
// kicked status counts only if card not changed zone since it was kicked
|
||||
if (card != null && card.getZoneChangeCounter(game) <= zoneChangeCounter +1) {
|
||||
for (OptionalAdditionalCost cost: kickerCosts) {
|
||||
if(cost.isActivated()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.resetKicker();
|
||||
public boolean isKicked(Game game, Ability source, String costText) {
|
||||
String key = getActivationKey(source, costText, game);
|
||||
if (activations.containsKey(key)) {
|
||||
return activations.get(key) > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -180,19 +171,26 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
return kickerCosts;
|
||||
}
|
||||
|
||||
private void activateKicker(OptionalAdditionalCost kickerCost, Game game) {
|
||||
kickerCost.activate();
|
||||
// remember zone change counter
|
||||
if (zoneChangeCounter == 0) {
|
||||
Card card = game.getCard(getSourceId());
|
||||
if (card != null) {
|
||||
zoneChangeCounter = card.getZoneChangeCounter(game);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Kicker source card not found");
|
||||
}
|
||||
private void activateKicker(OptionalAdditionalCost kickerCost, Ability source, Game game) {
|
||||
int amount = 1;
|
||||
String key = getActivationKey(source, kickerCost.getText(true), game);
|
||||
if (activations.containsKey(key)) {
|
||||
amount += activations.get(key);
|
||||
}
|
||||
activations.put(key, amount);
|
||||
}
|
||||
|
||||
private String getActivationKey(Ability source, String costText, Game game) {
|
||||
int zcc = source.getSourceObjectZoneChangeCounter();
|
||||
if (source.getSourceObjectZoneChangeCounter() == 0) {
|
||||
zcc = game.getState().getZoneChangeCounter(source.getSourceId());
|
||||
}
|
||||
if (zcc > 0 && (source.getAbilityType().equals(AbilityType.TRIGGERED) || source.getAbilityType().equals(AbilityType.STATIC))) {
|
||||
--zcc;
|
||||
}
|
||||
return String.valueOf(zcc) + ((kickerCosts.size() > 1) ? costText :"");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOptionalAdditionalCosts(Ability ability, Game game) {
|
||||
if (ability instanceof SpellAbility) {
|
||||
|
|
@ -208,8 +206,8 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
times = Integer.toString(activatedCount + 1) + (activatedCount == 0 ? " time ":" times ");
|
||||
}
|
||||
if (kickerCost.canPay(ability, sourceId, controllerId, game) &&
|
||||
player.chooseUse(Outcome.Benefit, new StringBuilder("Pay ").append(times).append(kickerCost.getText(false)).append(" ?").toString(), game)) {
|
||||
this.activateKicker(kickerCost, game);
|
||||
player.chooseUse(Outcome.Benefit, "Pay " + times + kickerCost.getText(false) + " ?", game)) {
|
||||
this.activateKicker(kickerCost, ability, game);
|
||||
for (Iterator it = ((Costs) kickerCost).iterator(); it.hasNext();) {
|
||||
Cost cost = (Cost) it.next();
|
||||
if (cost instanceof ManaCostsImpl) {
|
||||
|
|
|
|||
38
Mage/src/mage/abilities/keyword/MenaceAbility.java
Normal file
38
Mage/src/mage/abilities/keyword/MenaceAbility.java
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.effects.common.combat.CantBeBlockedByMoreThanOneSourceEffect;
|
||||
import mage.abilities.effects.common.combat.CantBeBlockedByOneEffect;
|
||||
import mage.constants.Zone;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class MenaceAbility extends StaticAbility {
|
||||
|
||||
public MenaceAbility() {
|
||||
super(Zone.BATTLEFIELD, new CantBeBlockedByOneEffect(2));
|
||||
}
|
||||
|
||||
public MenaceAbility(MenaceAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ability copy() {
|
||||
return new MenaceAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Menace <i>(This creature can't be blocked except by two or more creatures.)</i>";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -38,7 +38,6 @@ import mage.abilities.costs.CostsImpl;
|
|||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.SpliceCardEffectImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SpellAbilityType;
|
||||
|
|
@ -105,12 +104,12 @@ import mage.players.Player;
|
|||
public class SpliceOntoArcaneAbility extends SimpleStaticAbility {
|
||||
|
||||
private static final String KEYWORD_TEXT = "Splice onto Arcane";
|
||||
private Costs spliceCosts = new CostsImpl();
|
||||
private Costs<Cost> spliceCosts = new CostsImpl<>();
|
||||
private boolean nonManaCosts = false;
|
||||
|
||||
public SpliceOntoArcaneAbility(String manaString) {
|
||||
super(Zone.HAND, new SpliceOntoArcaneEffect());
|
||||
spliceCosts.add(new ManaCostsImpl(manaString));
|
||||
spliceCosts.add(new ManaCostsImpl<>(manaString));
|
||||
}
|
||||
|
||||
public SpliceOntoArcaneAbility(Cost cost) {
|
||||
|
|
@ -144,7 +143,6 @@ public class SpliceOntoArcaneAbility extends SimpleStaticAbility {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
class SpliceOntoArcaneEffect extends SpliceCardEffectImpl {
|
||||
|
||||
public SpliceOntoArcaneEffect() {
|
||||
|
|
@ -156,8 +154,6 @@ class SpliceOntoArcaneEffect extends SpliceCardEffectImpl {
|
|||
super(effect);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public SpliceOntoArcaneEffect copy() {
|
||||
return new SpliceOntoArcaneEffect(this);
|
||||
|
|
@ -175,12 +171,7 @@ class SpliceOntoArcaneEffect extends SpliceCardEffectImpl {
|
|||
splicedAbility.setSourceId(abilityToModify.getSourceId());
|
||||
spell.addSpellAbility(splicedAbility);
|
||||
for (Iterator it = ((SpliceOntoArcaneAbility) source).getSpliceCosts().iterator(); it.hasNext();) {
|
||||
Cost cost = (Cost) it.next();
|
||||
if (cost instanceof ManaCostsImpl) {
|
||||
spell.getSpellAbility().getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
||||
} else {
|
||||
spell.getSpellAbility().getCosts().add(cost.copy());
|
||||
}
|
||||
spell.getSpellAbility().getCosts().add(((Cost) it.next()).copy());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ public class StormAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getSourceId().equals(this.sourceId)) {
|
||||
StackObject spell = game.getStack().getStackObject(this.sourceId);
|
||||
if (event.getSourceId().equals(getSourceId())) {
|
||||
StackObject spell = game.getStack().getStackObject(getSourceId());
|
||||
if (spell instanceof Spell) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setValue("StormSpell", spell);
|
||||
|
|
@ -108,7 +108,7 @@ class StormEffect extends OneShotEffect {
|
|||
Spell spell = (Spell) this.getValue("StormSpell");
|
||||
if (spell != null) {
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers("Storm: " + spell.getName() + " will be copied " + stormCount + " time" + (stormCount > 1 ?"s":""));
|
||||
game.informPlayers("Storm: " + spell.getLogName() + " will be copied " + stormCount + " time" + (stormCount > 1 ?"s":""));
|
||||
}
|
||||
for (int i = 0; i < stormCount; i++) {
|
||||
Spell copy = spell.copySpell();
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@ public class TransformAbility extends SimpleStaticAbility {
|
|||
public static final String NO_SPELLS_TRANSFORM_RULE = "At the beginning of each upkeep, if no spells were cast last turn, transform {this}.";
|
||||
public static final String TWO_OR_MORE_SPELLS_TRANSFORM_RULE = "At the beginning of each upkeep, if a player cast two or more spells last turn, transform {this}.";
|
||||
|
||||
// this state value controlls if a permanent enters the battlefield already transformed
|
||||
public static final String VALUE_KEY_ENTER_TRANSFORMED = "EnterTransformed";
|
||||
|
||||
public TransformAbility() {
|
||||
super(Zone.BATTLEFIELD, new TransformEffect());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -359,6 +359,12 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
break;
|
||||
case STACK:
|
||||
StackObject stackObject = game.getStack().getSpell(getId());
|
||||
if (stackObject == null && (this instanceof SplitCard)) { // handle if half od Split cast is on the stack
|
||||
stackObject = game.getStack().getSpell(((SplitCard)this).getLeftHalfCard().getId());
|
||||
if (stackObject == null) {
|
||||
stackObject = game.getStack().getSpell(((SplitCard)this).getRightHalfCard().getId());
|
||||
}
|
||||
}
|
||||
if (stackObject != null) {
|
||||
game.getStack().remove(stackObject);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,9 +58,9 @@ public enum CardRepository {
|
|||
private static final String JDBC_URL = "jdbc:h2:file:./db/cards.h2;AUTO_SERVER=TRUE";
|
||||
private static final String VERSION_ENTITY_NAME = "card";
|
||||
// raise this if db structure was changed
|
||||
private static final long CARD_DB_VERSION = 38;
|
||||
private static final long CARD_DB_VERSION = 39;
|
||||
// raise this if new cards were added to the server
|
||||
private static final long CARD_CONTENT_VERSION = 17;
|
||||
private static final long CARD_CONTENT_VERSION = 20;
|
||||
|
||||
private final Random random = new Random();
|
||||
private Dao<CardInfo, Object> cardDao;
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ public enum ExpansionRepository {
|
|||
|
||||
private static final String JDBC_URL = "jdbc:h2:file:./db/cards.h2;AUTO_SERVER=TRUE";
|
||||
private static final String VERSION_ENTITY_NAME = "expansion";
|
||||
private static final long EXPANSION_DB_VERSION = 4;
|
||||
private static final long EXPANSION_CONTENT_VERSION = 7;
|
||||
private static final long EXPANSION_DB_VERSION = 5;
|
||||
private static final long EXPANSION_CONTENT_VERSION = 8;
|
||||
|
||||
private Dao<ExpansionInfo, Object> expansionDao;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ package mage.constants;
|
|||
public enum SpellAbilityType {
|
||||
BASE("Basic SpellAbility"),
|
||||
BASE_ALTERNATE("Basic SpellAbility Alternate"), // used for Overload, Flashback to know they must be handled as Alternate casting costs
|
||||
LAND_ALTERNATE("Basic SpellAbility Alternate Land"), // used for Lands with Morph to cast as Face Down creature
|
||||
FACE_DOWN_CREATURE("Face down creature"), // used for Lands with Morph to cast as Face Down creature
|
||||
SPLIT("Split SpellAbility"),
|
||||
SPLIT_FUSED("Split SpellAbility"),
|
||||
SPLIT_LEFT("LeftSplit SpellAbility"),
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ public enum CounterType {
|
|||
FADE("fade"),
|
||||
FATE("fate"),
|
||||
FEATHER("feather"),
|
||||
FLOOD("flood"),
|
||||
FUSE("fuse"),
|
||||
HATCHLING("hatchling"),
|
||||
HOOFPRINT("hoofprint"),
|
||||
|
|
|
|||
|
|
@ -29,10 +29,7 @@
|
|||
package mage.filter.common;
|
||||
|
||||
import mage.constants.AsThoughEffectType;
|
||||
import mage.filter.predicate.ObjectPlayer;
|
||||
import mage.filter.predicate.ObjectPlayerPredicate;
|
||||
import mage.filter.predicate.Predicate;
|
||||
import mage.game.Controllable;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,14 @@ public class CardAttribute implements Serializable {
|
|||
public CardAttribute(Card card) {
|
||||
color = card.getColor(null).copy();
|
||||
}
|
||||
|
||||
public CardAttribute(CardAttribute cardAttribute) {
|
||||
this.color = cardAttribute.color;
|
||||
}
|
||||
|
||||
public CardAttribute copy() {
|
||||
return new CardAttribute(this);
|
||||
}
|
||||
|
||||
public ObjectColor getColor() {
|
||||
return color;
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ public interface Game extends MageItem, Serializable {
|
|||
Card copyCard(Card cardToCopy, Ability source, UUID newController);
|
||||
|
||||
void addTriggeredAbility(TriggeredAbility ability);
|
||||
void addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility);
|
||||
UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility);
|
||||
void applyEffects();
|
||||
boolean checkStateAndTriggered();
|
||||
void playPriority(UUID activePlayerId, boolean resuming);
|
||||
|
|
|
|||
|
|
@ -56,8 +56,10 @@ import mage.watchers.common.CommanderInfoWatcher;
|
|||
|
||||
public abstract class GameCommanderImpl extends GameImpl {
|
||||
|
||||
static boolean CHECK_COMMANDER_DAMAGE = true;
|
||||
|
||||
private final Map<UUID, Cards> mulliganedCards = new HashMap<>();
|
||||
private final Set<CommanderInfoWatcher> commanderCombatWatcher = new HashSet<>();
|
||||
// private final Set<CommanderInfoWatcher> commanderCombatWatcher = new HashSet<>();
|
||||
|
||||
protected boolean alsoHand; // replace commander going to hand
|
||||
protected boolean alsoLibrary; // replace commander going to library
|
||||
|
|
@ -91,9 +93,8 @@ public abstract class GameCommanderImpl extends GameImpl {
|
|||
ability.addEffect(new CommanderCostModification(commander.getId()));
|
||||
ability.addEffect(new CommanderManaReplacementEffect(player.getId(), CardUtil.getColorIdentity(commander)));
|
||||
getState().setValue(commander.getId() + "_castCount", 0);
|
||||
CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), true);
|
||||
CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), CHECK_COMMANDER_DAMAGE);
|
||||
getState().getWatchers().add(watcher);
|
||||
this.commanderCombatWatcher.add(watcher);
|
||||
watcher.addCardInfoToCommander(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -185,12 +186,13 @@ public abstract class GameCommanderImpl extends GameImpl {
|
|||
*/
|
||||
@Override
|
||||
protected boolean checkStateBasedActions() {
|
||||
for (CommanderInfoWatcher damageWatcher: commanderCombatWatcher) {
|
||||
for (Player player: getPlayers().values()) {
|
||||
CommanderInfoWatcher damageWatcher = (CommanderInfoWatcher) getState().getWatchers().get("CommanderCombatDamageWatcher", player.getCommanderId());
|
||||
for(Map.Entry<UUID, Integer> entrySet : damageWatcher.getDamageToPlayer().entrySet()){
|
||||
if (entrySet.getValue() > 20) {
|
||||
Player player = getPlayer(entrySet.getKey());
|
||||
if (player != null && player.isInGame()){
|
||||
player.lost(this);
|
||||
Player opponent = getPlayer(entrySet.getKey());
|
||||
if (opponent != null && player.isInGame()){
|
||||
opponent.lost(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ import mage.watchers.Watchers;
|
|||
import mage.watchers.common.BlockedAttackerWatcher;
|
||||
import mage.watchers.common.BloodthirstWatcher;
|
||||
import mage.watchers.common.CastSpellLastTurnWatcher;
|
||||
import mage.watchers.common.DamageDoneWatcher;
|
||||
import mage.watchers.common.MorbidWatcher;
|
||||
import mage.watchers.common.PlayerDamagedBySourceWatcher;
|
||||
import mage.watchers.common.PlayerLostLifeWatcher;
|
||||
|
|
@ -912,6 +913,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
watchers.add(new SoulbondWatcher());
|
||||
watchers.add(new PlayerLostLifeWatcher());
|
||||
watchers.add(new BlockedAttackerWatcher());
|
||||
watchers.add(new DamageDoneWatcher());
|
||||
|
||||
//20100716 - 103.5
|
||||
for (UUID playerId: state.getPlayerList(startingPlayerId)) {
|
||||
|
|
@ -1144,6 +1146,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
int bookmark = 0;
|
||||
clearAllBookmarks();
|
||||
try {
|
||||
applyEffects();
|
||||
while (!isPaused() && !gameOver(null) && !this.getTurn().isEndTurnRequested()) {
|
||||
if (!resuming) {
|
||||
state.getPlayers().resetPassed();
|
||||
|
|
@ -1383,11 +1386,12 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility) {
|
||||
public UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility) {
|
||||
DelayedTriggeredAbility newAbility = delayedAbility.copy();
|
||||
newAbility.newId();
|
||||
newAbility.init(this);
|
||||
state.addDelayedTriggeredAbility(newAbility);
|
||||
return newAbility.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -171,6 +171,9 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
for (Map.Entry<UUID, CardState> entry: state.cardState.entrySet()) {
|
||||
cardState.put(entry.getKey(), entry.getValue().copy());
|
||||
}
|
||||
for (Map.Entry<UUID, CardAttribute> entry: state.cardAttribute.entrySet()) {
|
||||
cardAttribute.put(entry.getKey(), entry.getValue().copy());
|
||||
}
|
||||
this.zoneChangeCounter.putAll(state.zoneChangeCounter);
|
||||
this.copiedCards.putAll(state.copiedCards);
|
||||
this.permanentOrderNumber = state.permanentOrderNumber;
|
||||
|
|
@ -208,6 +211,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
this.zones = state.zones;
|
||||
this.simultaneousEvents = state.simultaneousEvents;
|
||||
this.cardState = state.cardState;
|
||||
this.cardAttribute = state.cardAttribute;
|
||||
this.zoneChangeCounter = state.zoneChangeCounter;
|
||||
this.copiedCards = state.copiedCards;
|
||||
this.permanentOrderNumber = state.permanentOrderNumber;
|
||||
|
|
|
|||
|
|
@ -247,7 +247,9 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
for (Ability ability : entry.getValue()) {
|
||||
UUID defenderId = effect.mustAttackDefender(ability, game);
|
||||
if (defenderId != null) {
|
||||
defendersForcedToAttack.add(defenderId);
|
||||
if (defenders.contains(defenderId)) {
|
||||
defendersForcedToAttack.add(defenderId);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import java.util.UUID;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.keyword.TransformAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.LevelerCard;
|
||||
import mage.constants.Zone;
|
||||
|
|
@ -65,6 +66,13 @@ public class PermanentCard extends PermanentImpl {
|
|||
if (card instanceof LevelerCard) {
|
||||
maxLevelCounters = ((LevelerCard) card).getMaxLevelCounters();
|
||||
}
|
||||
if (canTransform()) {
|
||||
if (game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getId()) != null) {
|
||||
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getId(), null);
|
||||
setTransformed(true);
|
||||
TransformAbility.transform(this, getSecondCardFace(), game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PermanentCard(final PermanentCard permanent) {
|
||||
|
|
|
|||
|
|
@ -372,6 +372,11 @@ public class Spell extends StackObjImpl implements Card {
|
|||
|
||||
@Override
|
||||
public List<CardType> getCardType() {
|
||||
if (this.getSpellAbility().getSpellAbilityType().equals(SpellAbilityType.FACE_DOWN_CREATURE)) {
|
||||
List<CardType> cardTypes = new ArrayList<>();
|
||||
cardTypes.add(CardType.CREATURE);
|
||||
return cardTypes;
|
||||
}
|
||||
if (this.getSpellAbility() instanceof BestowAbility) {
|
||||
List<CardType> cardTypes = new ArrayList<>();
|
||||
cardTypes.addAll(card.getCardType());
|
||||
|
|
|
|||
|
|
@ -209,21 +209,20 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
protected Set<UUID> playersUnderYourControl = new HashSet<>();
|
||||
|
||||
protected Set<UUID> usersAllowedToSeeHandCards = new HashSet<>();
|
||||
protected boolean requestsAllowedToSeeHandCards = true;
|
||||
|
||||
protected List<UUID> attachments = new ArrayList<>();
|
||||
|
||||
protected boolean topCardRevealed = false;
|
||||
|
||||
// 800.4i When a player leaves the game, any continuous effects with durations that last until that player's next turn
|
||||
// or until a specific point in that turn will last until that turn would have begun.
|
||||
// or until a specific point in that turn will last until that turn would have begun.
|
||||
// They neither expire immediately nor last indefinitely.
|
||||
protected boolean reachedNextTurnAfterLeaving = false;
|
||||
|
||||
// indicates that the spell with the set sourceId can be cast with an alternate mana costs (can also be no mana costs)
|
||||
protected UUID castSourceIdWithAlternateMana;
|
||||
protected ManaCosts castSourceIdManaCosts;
|
||||
|
||||
|
||||
// indicates that the player is in mana payment phase
|
||||
protected boolean payManaMode = false;
|
||||
|
||||
|
|
@ -369,7 +368,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
this.canPaySacrificeCost = player.canPaySacrificeCost();
|
||||
this.loseByZeroOrLessLife = player.canLoseByZeroOrLessLife();
|
||||
this.canPlayCardsFromGraveyard = player.canPlayCardsFromGraveyard();
|
||||
this.alternativeSourceCosts.addAll(player.getAlternativeSourceCosts());
|
||||
this.alternativeSourceCosts.addAll(player.getAlternativeSourceCosts());
|
||||
|
||||
this.topCardRevealed = player.isTopCardRevealed();
|
||||
this.playersUnderYourControl.clear();
|
||||
|
|
@ -444,7 +443,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
this.payManaMode = false;
|
||||
this.setLife(game.getLife(), game);
|
||||
this.setReachedNextTurnAfterLeaving(false);
|
||||
|
||||
|
||||
this.castSourceIdWithAlternateMana = null;
|
||||
this.castSourceIdManaCosts = null;
|
||||
}
|
||||
|
|
@ -575,7 +574,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
/**
|
||||
* returns true if the player has the control itself - false if the player is controlled by another player
|
||||
* @return
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean isGameUnderControl() {
|
||||
|
|
@ -704,11 +703,14 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (random) {
|
||||
for (int i = 0; i < amount; i++) {
|
||||
Card card = this.getHand().getRandom(game);
|
||||
discardedCards.add(card);
|
||||
discard(card, source, game);
|
||||
if(card != null) {
|
||||
discardedCards.add(card);
|
||||
discard(card, source, game);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TargetDiscard target = new TargetDiscard(amount, amount, new FilterCard(CardUtil.numberToText(amount, "a") + " card" + (amount > 1 ? "s" : "")), playerId);
|
||||
int possibleAmount = Math.min(getHand().size(), amount);
|
||||
TargetDiscard target = new TargetDiscard(possibleAmount, possibleAmount, new FilterCard(CardUtil.numberToText(possibleAmount, "a") + " card" + (possibleAmount > 1 ? "s" : "")), playerId);
|
||||
choose(Outcome.Discard, target, source == null ? null : source.getSourceId(), game);
|
||||
for (UUID cardId : target.getTargets()) {
|
||||
Card card = this.getHand().get(cardId, game);
|
||||
|
|
@ -802,7 +804,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
attachedToPlayer.removeAttachment(permanent, game);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (permanent.getPairedCard() != null) {
|
||||
Permanent pairedCard = game.getPermanent(permanent.getPairedCard());
|
||||
|
|
@ -876,7 +878,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
while (isInGame() && cards.size() > 1) {
|
||||
this.choose(Outcome.Neutral, cards, target, game);
|
||||
UUID targetObjectId = target.getFirstTarget();
|
||||
cards.remove(targetObjectId);
|
||||
cards.remove(targetObjectId);
|
||||
moveObjectToLibrary(targetObjectId, source.getSourceId(), game, true, false);
|
||||
target.clearChosen();
|
||||
}
|
||||
|
|
@ -917,7 +919,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return castSourceIdManaCosts;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isInPayManaMode() {
|
||||
return payManaMode;
|
||||
|
|
@ -947,7 +949,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
spellAbility.getManaCosts().add(alternateCosts.copy());
|
||||
spellAbility.getManaCostsToPay().clear();
|
||||
spellAbility.getManaCostsToPay().add(alternateCosts.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
setCastSourceIdWithAlternateMana(null, null);
|
||||
if (spell.activate(game, noMana)) {
|
||||
|
|
@ -987,7 +989,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
}
|
||||
if (found) {
|
||||
SpellAbility spellAbility = new SpellAbility(null, "", game.getState().getZone(card.getId()), SpellAbilityType.LAND_ALTERNATE);
|
||||
SpellAbility spellAbility = new SpellAbility(null, "", game.getState().getZone(card.getId()), SpellAbilityType.FACE_DOWN_CREATURE);
|
||||
spellAbility.setControllerId(this.getId());
|
||||
spellAbility.setSourceId(card.getId());
|
||||
if (cast(spellAbility, game, false)) {
|
||||
|
|
@ -1528,7 +1530,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public String getLogName() {
|
||||
return GameLog.getColoredPlayerName(name);
|
||||
return GameLog.getColoredPlayerName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -1669,11 +1671,11 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
sourceControllerId = ((Spell) source).getControllerId();
|
||||
} else if (source instanceof Card) {
|
||||
sourceAbilities = ((Card) source).getAbilities(game);
|
||||
sourceControllerId = ((Card) source).getOwnerId();
|
||||
sourceControllerId = ((Card) source).getOwnerId();
|
||||
} else if (source instanceof CommandObject){
|
||||
sourceControllerId = ((CommandObject) source).getControllerId();
|
||||
sourceAbilities = ((CommandObject) source).getAbilities();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sourceAbilities = ((Permanent) source).getAbilities(game);
|
||||
sourceControllerId = ((Permanent) source).getControllerId();
|
||||
|
|
@ -2426,7 +2428,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NON_HAND_ZONE, this.getId(), game)) {
|
||||
for (Ability ability : card.getAbilities()) {
|
||||
if (ability.getZone().match(Zone.HAND)) {
|
||||
ability.setControllerId(this.getId()); // controller must be set for case owner != caster
|
||||
ability.setControllerId(this.getId()); // controller must be set for case owner != caster
|
||||
if (ability instanceof ActivatedAbility) {
|
||||
if (((ActivatedAbility) ability).canActivate(playerId, game)) {
|
||||
playable.add(ability);
|
||||
|
|
@ -2537,7 +2539,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
* @return
|
||||
*/
|
||||
private boolean shouldSkipGettingPlayable(Game game) {
|
||||
if (game.getStep() == null) { // happens at the start of the game
|
||||
if (game.getStep() == null) { // happens at the start of the game
|
||||
return true;
|
||||
}
|
||||
for (Entry<PhaseStep, Step.StepPart> phaseStep : silentPhaseSteps.entrySet()) {
|
||||
|
|
@ -2838,19 +2840,31 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
@Override
|
||||
public boolean moveCards(Cards cards, Zone fromZone, Zone toZone, Ability source, Game game) {
|
||||
ArrayList<Card> cardList = new ArrayList<>();
|
||||
cardList.addAll(cards.getCards(game));
|
||||
for (UUID cardId: cards) {
|
||||
if (fromZone.equals(Zone.BATTLEFIELD)) {
|
||||
Permanent permanent = game.getPermanent(cardId);
|
||||
if (permanent != null) {
|
||||
cardList.add(permanent);
|
||||
}
|
||||
} else {
|
||||
Card card = game.getCard(cardId);
|
||||
if (card != null) {
|
||||
cardList.add(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
return moveCards(cardList, fromZone, toZone, source, game);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean moveCards(Card card, Zone fromZone, Zone toZone, Ability source, Game game) {
|
||||
ArrayList<Card> cardList = new ArrayList<>();
|
||||
if (card != null) {
|
||||
cardList.add(card);
|
||||
}
|
||||
return moveCards(cardList, fromZone, toZone, source, game);
|
||||
return moveCards(cardList, fromZone, toZone, source, game);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean moveCards(List<Card> cards, Zone fromZone, Zone toZone, Ability source, Game game) {
|
||||
if (cards.isEmpty()) {
|
||||
|
|
@ -2858,13 +2872,13 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
game.fireEvent(new ZoneChangeGroupEvent(cards, source == null ? null : source.getSourceId(), this.getId(), fromZone, toZone));
|
||||
switch(toZone) {
|
||||
case EXILED:
|
||||
case EXILED:
|
||||
boolean result = false;
|
||||
for(Card card: cards) {
|
||||
result |= moveCardToExileWithInfo(card, null, "", source == null ? null : source.getSourceId(), game, fromZone, true);
|
||||
}
|
||||
return result;
|
||||
case GRAVEYARD:
|
||||
return result;
|
||||
case GRAVEYARD:
|
||||
return moveCardsToGraveyardWithInfo(cards, source, game, fromZone);
|
||||
case HAND:
|
||||
result = false;
|
||||
|
|
@ -2874,9 +2888,9 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return result;
|
||||
default:
|
||||
throw new UnsupportedOperationException("to Zone not supported yet");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game, Zone fromZone) {
|
||||
return this.moveCardToHandWithInfo(card, sourceId, game, fromZone, true);
|
||||
|
|
@ -2898,7 +2912,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
default:
|
||||
sb.append(fromZone != null ? new StringBuilder(" from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" ") : "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
sb.append(card.getOwnerId().equals(this.getId()) ? "into his or her hand" : "into its owner's hand");
|
||||
game.informPlayers(sb.toString());
|
||||
}
|
||||
|
|
@ -2906,10 +2920,10 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean moveCardsToGraveyardWithInfo(List<Card> allCards, Ability source, Game game, Zone fromZone) {
|
||||
boolean result = true;
|
||||
boolean result = true;
|
||||
UUID sourceId = source == null ? null : source.getSourceId();
|
||||
while (!allCards.isEmpty()) {
|
||||
// identify cards from one owner
|
||||
|
|
@ -2934,19 +2948,21 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (choosingPlayer == null) {
|
||||
continue;
|
||||
}
|
||||
boolean chooseOrder = true;
|
||||
if (cards.size() > 2) {
|
||||
chooseOrder = choosingPlayer.chooseUse(Outcome.Neutral, "Would you like to choose the order the cards go to graveyard?", game);
|
||||
boolean chooseOrder = false;
|
||||
if (userData.askMoveToGraveOrder()) {
|
||||
if (cards.size() > 3) {
|
||||
chooseOrder = choosingPlayer.chooseUse(Outcome.Neutral, "Would you like to choose the order the cards go to graveyard?", game);
|
||||
}
|
||||
}
|
||||
if (chooseOrder) {
|
||||
TargetCard target = new TargetCard(fromZone, new FilterCard("card to put on the top of your graveyard (last one chosen will be topmost)"));
|
||||
target.setRequired(true);
|
||||
while (choosingPlayer.isInGame() && cards.size() > 1) {
|
||||
choosingPlayer.chooseTarget(Outcome.Neutral, cards, target, source, game);
|
||||
UUID targetObjectId = target.getFirstTarget();
|
||||
UUID targetObjectId = target.getFirstTarget();
|
||||
Card card = cards.get(targetObjectId, game);
|
||||
cards.remove(targetObjectId);
|
||||
if (card != null) {
|
||||
cards.remove(targetObjectId);
|
||||
if (card != null) {
|
||||
result &= choosingPlayer.moveCardToGraveyardWithInfo(card, sourceId, game, fromZone);
|
||||
}
|
||||
target.clearChosen();
|
||||
|
|
@ -2959,11 +2975,11 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
result &= choosingPlayer.moveCardToGraveyardWithInfo(card, sourceId, game, fromZone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, Game game, Zone fromZone) {
|
||||
boolean result = false;
|
||||
|
|
@ -3045,7 +3061,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped) {
|
||||
return this.putOntoBattlefieldWithInfo(card, game, fromZone, sourceId, tapped, false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped, boolean facedown) {
|
||||
boolean result = false;
|
||||
|
|
@ -3109,7 +3125,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean isRequestToShowHandCardsAllowed() {
|
||||
return userData.allowRequestShowHandCards();
|
||||
return userData.isAllowRequestShowHandCards();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -16,10 +16,11 @@ public class UserData implements Serializable {
|
|||
protected boolean confirmEmptyManaPool;
|
||||
protected UserSkipPrioritySteps userSkipPrioritySteps;
|
||||
protected String flagName;
|
||||
protected boolean askMoveToGraveOrder;
|
||||
|
||||
public UserData(UserGroup userGroup, int avatarId, boolean showAbilityPickerForced,
|
||||
boolean allowRequestShowHandCards, boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps,
|
||||
String flagName) {
|
||||
String flagName, boolean askMoveToGraveOrder) {
|
||||
this.groupId = userGroup.getGroupId();
|
||||
this.avatarId = avatarId;
|
||||
this.showAbilityPickerForced = showAbilityPickerForced;
|
||||
|
|
@ -27,6 +28,7 @@ public class UserData implements Serializable {
|
|||
this.userSkipPrioritySteps = userSkipPrioritySteps;
|
||||
this.confirmEmptyManaPool = confirmEmptyManaPool;
|
||||
this.flagName = flagName;
|
||||
this.askMoveToGraveOrder = askMoveToGraveOrder;
|
||||
}
|
||||
|
||||
public void setGroupId(int groupId) {
|
||||
|
|
@ -49,20 +51,16 @@ public class UserData implements Serializable {
|
|||
return showAbilityPickerForced;
|
||||
}
|
||||
|
||||
public boolean isAllowRequestShowHandCards() {
|
||||
return allowRequestShowHandCards;
|
||||
}
|
||||
|
||||
public void setShowAbilityPickerForced(boolean showAbilityPickerForced) {
|
||||
this.showAbilityPickerForced = showAbilityPickerForced;
|
||||
}
|
||||
|
||||
public void setAllowRequestShowHandCards(boolean allowRequestShowHandCards) {
|
||||
this.allowRequestShowHandCards = allowRequestShowHandCards;
|
||||
public boolean isAllowRequestShowHandCards() {
|
||||
return allowRequestShowHandCards;
|
||||
}
|
||||
|
||||
public boolean allowRequestShowHandCards() {
|
||||
return allowRequestShowHandCards;
|
||||
public void setAllowRequestShowHandCards(boolean allowRequestShowHandCards) {
|
||||
this.allowRequestShowHandCards = allowRequestShowHandCards;
|
||||
}
|
||||
|
||||
public UserSkipPrioritySteps getUserSkipPrioritySteps() {
|
||||
|
|
@ -84,5 +82,13 @@ public class UserData implements Serializable {
|
|||
public String getFlagName() {
|
||||
return flagName;
|
||||
}
|
||||
|
||||
public boolean askMoveToGraveOrder() {
|
||||
return askMoveToGraveOrder;
|
||||
}
|
||||
|
||||
public void setAskMoveToGraveOrder(boolean askMoveToGraveOrder) {
|
||||
this.askMoveToGraveOrder = askMoveToGraveOrder;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
53
Mage/src/mage/watchers/common/AttackedThisCombatWatcher.java
Normal file
53
Mage/src/mage/watchers/common/AttackedThisCombatWatcher.java
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.watchers.common;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import mage.MageObjectReference;
|
||||
import mage.constants.WatcherScope;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class AttackedThisCombatWatcher extends Watcher {
|
||||
|
||||
public Set<MageObjectReference> attackedThisTurnCreatures = new HashSet<>();
|
||||
|
||||
public AttackedThisCombatWatcher() {
|
||||
super("AttackedThisCombat", WatcherScope.GAME);
|
||||
}
|
||||
|
||||
public AttackedThisCombatWatcher(final AttackedThisCombatWatcher watcher) {
|
||||
super(watcher);
|
||||
this.attackedThisTurnCreatures.addAll(watcher.attackedThisTurnCreatures);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if (event.getType() == GameEvent.EventType.BEGIN_COMBAT_STEP_PRE) {
|
||||
this.attackedThisTurnCreatures.clear();
|
||||
}
|
||||
if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED) {
|
||||
this.attackedThisTurnCreatures.add(new MageObjectReference(event.getSourceId(),game));
|
||||
}
|
||||
}
|
||||
|
||||
public Set<MageObjectReference> getAttackedThisTurnCreatures() {
|
||||
return this.attackedThisTurnCreatures;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttackedThisCombatWatcher copy() {
|
||||
return new AttackedThisCombatWatcher(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -40,6 +40,7 @@ import mage.watchers.Watcher;
|
|||
*/
|
||||
public class AttackedThisTurnWatcher extends Watcher {
|
||||
|
||||
// TODO: use MageObjectReference instead of UUID
|
||||
public Set<UUID> attackedThisTurnCreatures = new HashSet<>();
|
||||
|
||||
public AttackedThisTurnWatcher() {
|
||||
|
|
|
|||
67
Mage/src/mage/watchers/common/DamageDoneWatcher.java
Normal file
67
Mage/src/mage/watchers/common/DamageDoneWatcher.java
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.watchers.common;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import mage.MageObjectReference;
|
||||
import mage.constants.WatcherScope;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamageEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class DamageDoneWatcher extends Watcher {
|
||||
|
||||
// which object did how much damage during the turn
|
||||
public Map<MageObjectReference, Integer> damagingObjects = new HashMap<>();
|
||||
|
||||
public DamageDoneWatcher() {
|
||||
super("DamageDone", WatcherScope.GAME);
|
||||
}
|
||||
|
||||
public DamageDoneWatcher(final DamageDoneWatcher watcher) {
|
||||
super(watcher);
|
||||
this.damagingObjects.putAll(damagingObjects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DamageDoneWatcher copy() {
|
||||
return new DamageDoneWatcher(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
switch(event.getType()) {
|
||||
case DAMAGED_CREATURE:
|
||||
case DAMAGED_PLANESWALKER:
|
||||
case DAMAGED_PLAYER:
|
||||
{
|
||||
MageObjectReference mor = new MageObjectReference(event.getSourceId(), game);
|
||||
int count = damagingObjects.containsKey(mor) ? damagingObjects.get(mor) : 0;
|
||||
damagingObjects.put(mor, count + event.getAmount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
damagingObjects.clear();
|
||||
}
|
||||
|
||||
public int damageDone(UUID objectId, int zoneChangeCounter, Game game) {
|
||||
MageObjectReference mor = new MageObjectReference(objectId, zoneChangeCounter, game);
|
||||
return damagingObjects.containsKey(mor) ? damagingObjects.get(mor) : 0;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue