* Game log - triggered abilities are now logged as they go to stack. Some minor formatting.

This commit is contained in:
LevelX2 2014-03-17 08:37:54 +01:00
parent 4232a3b7f1
commit 2f8ac76417
15 changed files with 338 additions and 183 deletions

View file

@ -28,14 +28,14 @@
package mage.sets.fifthedition; package mage.sets.fifthedition;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInHand;
@ -101,7 +101,7 @@ class BrainstormEffect extends OneShotEffect<BrainstormEffect> {
Card card = player.getHand().get(target.getFirstTarget(), game); Card card = player.getHand().get(target.getFirstTarget(), game);
if (card != null) { if (card != null) {
player.getHand().remove(card); player.getHand().remove(card);
card.moveToZone(Zone.LIBRARY, source.getId(), game, true); card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true);
} }
return true; return true;
} }

View file

@ -29,7 +29,6 @@ package mage.sets.innistrad;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ContinuousEffectImpl;
@ -48,6 +47,7 @@ import mage.filter.FilterCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCardInYourGraveyard;
/** /**
@ -112,9 +112,9 @@ class SnapcasterMageEffect extends ContinuousEffectImpl<SnapcasterMageEffect> {
@Override @Override
public void init(Ability source, Game game) { public void init(Ability source, Game game) {
Card card = game.getCard(targetPointer.getFirst(game, source)); Card card = game.getCard(targetPointer.getFirst(game, source));
MageObject sourceObject = game.getObject(source.getSourceId()); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (card != null && sourceObject != null) { if (card != null && sourcePermanent != null) {
game.informPlayers(new StringBuilder(sourceObject.getName()).append(" gives flashback to ").append(card.getName()).toString()); game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(" gives flashback to ").append(card.getName()).toString());
} }
} }

View file

@ -36,6 +36,7 @@ import mage.abilities.effects.common.CounterUnlessPaysEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.filter.FilterSpell; import mage.filter.FilterSpell;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AnotherCardPredicate;
import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.target.TargetSpell; import mage.target.TargetSpell;
@ -49,6 +50,7 @@ public class SpellPierce extends CardImpl<SpellPierce> {
static { static {
filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE)));
filter.add(new AnotherCardPredicate());
} }
public SpellPierce(UUID ownerId) { public SpellPierce(UUID ownerId) {

View file

@ -419,5 +419,14 @@ public interface Ability extends Controllable, Serializable {
* @param abilityWord * @param abilityWord
*/ */
void setAbilityWord(AbilityWord abilityWord); void setAbilityWord(AbilityWord abilityWord);
/**
* Creates the message about the ability casting/triggering/activating to post in the game log
* before the ability resolves.
*
* @param game
* @return
*/
String getGameLogMessage(Game game);
} }

View file

@ -57,10 +57,13 @@ import mage.constants.AbilityType;
import mage.constants.AbilityWord; import mage.constants.AbilityWord;
import mage.constants.EffectType; import mage.constants.EffectType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SpellAbilityType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.command.Emblem; import mage.game.command.Emblem;
import mage.game.permanent.PermanentCard; import mage.game.permanent.PermanentCard;
import mage.game.stack.Spell;
import mage.game.stack.StackAbility;
import mage.players.Player; import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.Targets; import mage.target.Targets;
@ -750,7 +753,134 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
public void setAbilityWord(AbilityWord abilityWord) { public void setAbilityWord(AbilityWord abilityWord) {
this.abilityWord = abilityWord; this.abilityWord = abilityWord;
} }
@Override
public String getGameLogMessage(Game game) {
if (game.isSimulation()) {
return "";
}
MageObject object = game.getObject(this.sourceId);
return new StringBuilder(" activates: ")
.append(object != null ? this.formatRule(modes.getText(), object.getName()) :modes.getText())
.append(" from ")
.append(getMessageText(game)).toString();
}
protected String getMessageText(Game game) {
StringBuilder sb = new StringBuilder();
MageObject object = game.getObject(this.sourceId);
if (object == null) {
object = game.getLastKnownInformation(this.sourceId, Zone.BATTLEFIELD);
}
if (object != null) {
if (object instanceof StackAbility) {
Card card = game.getCard(((StackAbility) object).getSourceId());
if (card != null) {
sb.append(card.getName());
} else {
sb.append(object.getName());
}
} else {
if (object instanceof Spell) {
Spell<?> spell = (Spell<?>) object;
String castText = spell.getSpellAbility().toString();
sb.append((castText.startsWith("Cast ") ? castText.substring(5):castText));
if (spell.getFromZone() == Zone.GRAVEYARD) {
sb.append(" from graveyard");
}
sb.append(getOptionalTextSuffix(game, spell));
} else {
sb.append(object.getName());
}
}
} else {
sb.append("unknown");
}
if (object instanceof Spell && ((Spell) object).getSpellAbilities().size() > 1) {
if (((Spell) object).getSpellAbility().getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)) {
Spell<?> spell = (Spell<?>) object;
int i = 0;
for (SpellAbility spellAbility : spell.getSpellAbilities()) {
i++;
String half;
if (i == 1) {
half = " left";
} else {
half = " right";
}
if (spellAbility.getTargets().size() > 0) {
sb.append(half).append(" half targeting ");
for (Target target: spellAbility.getTargets()) {
sb.append(target.getTargetedName(game));
}
}
}
} else {
Spell<?> spell = (Spell<?>) object;
int i = 0;
for (SpellAbility spellAbility : spell.getSpellAbilities()) {
i++;
if ( i > 1) {
sb.append(" splicing ");
if (spellAbility.name.length() > 5 && spellAbility.name.startsWith("Cast ")) {
sb.append(spellAbility.name.substring(5));
} else {
sb.append(spellAbility.name);
}
}
appendTargetDescriptionForLog(sb, spellAbility.getTargets(), game);
}
}
} else if (object instanceof Spell && ((Spell) object).getSpellAbility().getModes().size() > 1) {
Modes spellModes = ((Spell) object).getSpellAbility().getModes();
int item = 0;
for (Mode mode : spellModes.values()) {
item++;
if (spellModes.getSelectedModes().contains(mode.getId())) {
spellModes.setMode(mode);
sb.append(" (mode ").append(item).append(")");
appendTargetDescriptionForLog(sb, getTargets(), game);
}
}
} else {
appendTargetDescriptionForLog(sb, getTargets(), game);
}
for (Choice choice :this.getChoices()) {
sb.append(" - ").append(choice.getMessage()).append(": ").append(choice.getChoice());
}
return sb.toString();
}
protected void appendTargetDescriptionForLog(StringBuilder sb, Targets targets, Game game) {
if (targets.size() > 0) {
String usedVerb = null;
for (Target target : targets) {
if (!target.isNotTarget()) {
if (usedVerb == null || usedVerb.equals(" choosing ")) {
usedVerb = " targeting ";
sb.append(usedVerb);
}
} else if (target.isNotTarget() && (usedVerb == null || usedVerb.equals(" targeting "))) {
usedVerb = " choosing ";
sb.append(usedVerb);
}
sb.append(target.getTargetedName(game));
}
}
}
private String getOptionalTextSuffix(Game game, Spell spell) {
StringBuilder sb = new StringBuilder();
for (Ability ability : (Abilities<Ability>) spell.getAbilities()) {
if (ability instanceof OptionalAdditionalSourceCosts) {
sb.append(((OptionalAdditionalSourceCosts) ability).getCastMessageSuffix());
}
if (ability instanceof AlternativeSourceCosts) {
sb.append(((AlternativeSourceCosts) ability).getCastMessageSuffix());
}
}
return sb.toString();
}
} }

View file

@ -38,6 +38,4 @@ import mage.game.Game;
public interface ActivatedAbility extends Ability { public interface ActivatedAbility extends Ability {
boolean canActivate(UUID playerId, Game game); boolean canActivate(UUID playerId, Game game);
String getActivatedMessage(Game game);
} }

View file

@ -50,7 +50,6 @@ import mage.game.Game;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.game.stack.StackAbility; import mage.game.stack.StackAbility;
import mage.target.Target; import mage.target.Target;
import mage.target.Targets;
/** /**
@ -208,133 +207,134 @@ public abstract class ActivatedAbilityImpl<T extends ActivatedAbilityImpl<T>> ex
return false; return false;
} }
@Override // @Override
public String getActivatedMessage(Game game) { // public String getGameLogMessage(Game game) {
if (game.isSimulation()) { // if (game.isSimulation()) {
return ""; // return "";
} // }
MageObject object = game.getObject(this.sourceId); // MageObject object = game.getObject(this.sourceId);
return new StringBuilder(" activates: ") // return new StringBuilder(" activates: ")
.append(object != null ? this.formatRule(modes.getText(), object.getName()) :modes.getText()) // .append(object != null ? this.formatRule(modes.getText(), object.getName()) :modes.getText())
.append(" from ") // .append(" from ")
.append(getMessageText(game)).toString(); // .append(getMessageText(game)).toString();
} // }
//
// @Override
// protected String getMessageText(Game game) {
// StringBuilder sb = new StringBuilder();
// MageObject object = game.getObject(this.sourceId);
// if (object == null) {
// object = game.getLastKnownInformation(this.sourceId, Zone.BATTLEFIELD);
// }
// if (object != null) {
// if (object instanceof StackAbility) {
// Card card = game.getCard(((StackAbility) object).getSourceId());
// if (card != null) {
// sb.append(card.getName());
// } else {
// sb.append(object.getName());
// }
// } else {
// if (object instanceof Spell) {
// Spell<?> spell = (Spell<?>) object;
// String castText = spell.getSpellAbility().toString();
// sb.append((castText.startsWith("Cast ") ? castText.substring(5):castText));
// if (spell.getFromZone() == Zone.GRAVEYARD) {
// sb.append(" from graveyard");
// }
// sb.append(getOptionalTextSuffix(game, spell));
// } else {
// sb.append(object.getName());
// }
// }
// } else {
// sb.append("unknown");
// }
// if (object instanceof Spell && ((Spell) object).getSpellAbilities().size() > 1) {
// if (((Spell) object).getSpellAbility().getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)) {
// Spell<?> spell = (Spell<?>) object;
// int i = 0;
// for (SpellAbility spellAbility : spell.getSpellAbilities()) {
// i++;
// String half;
// if (i == 1) {
// half = " left";
// } else {
// half = " right";
// }
// if (spellAbility.getTargets().size() > 0) {
// sb.append(half).append(" half targeting ");
// for (Target target: spellAbility.getTargets()) {
// sb.append(target.getTargetedName(game));
// }
// }
// }
// } else {
// Spell<?> spell = (Spell<?>) object;
// int i = 0;
// for (SpellAbility spellAbility : spell.getSpellAbilities()) {
// i++;
// if ( i > 1) {
// sb.append(" splicing ");
// if (spellAbility.name.length() > 5 && spellAbility.name.startsWith("Cast ")) {
// sb.append(spellAbility.name.substring(5));
// } else {
// sb.append(spellAbility.name);
// }
// }
// appendTargetDescriptionForLog(sb, spellAbility.getTargets(), game);
// }
// }
// } else if (object instanceof Spell && ((Spell) object).getSpellAbility().getModes().size() > 1) {
// Modes spellModes = ((Spell) object).getSpellAbility().getModes();
// int item = 0;
// for (Mode mode : spellModes.values()) {
// item++;
// if (spellModes.getSelectedModes().contains(mode.getId())) {
// spellModes.setMode(mode);
// sb.append(" (mode ").append(item).append(")");
// appendTargetDescriptionForLog(sb, getTargets(), game);
// }
// }
// } else {
// appendTargetDescriptionForLog(sb, getTargets(), game);
// }
// for (Choice choice :this.getChoices()) {
// sb.append(" - ").append(choice.getMessage()).append(": ").append(choice.getChoice());
// }
// return sb.toString();
// }
protected String getMessageText(Game game) { // private void appendTargetDescriptionForLog(StringBuilder sb, Targets targets, Game game) {
StringBuilder sb = new StringBuilder(); // if (targets.size() > 0) {
MageObject object = game.getObject(this.sourceId); // String usedVerb = null;
if (object == null) { // for (Target target: targets) {
object = game.getLastKnownInformation(this.sourceId, Zone.BATTLEFIELD); // if (!target.isNotTarget()) {
} // if (usedVerb == null || usedVerb.equals(" choosing ")) {
if (object != null) { // usedVerb = " targeting ";
if (object instanceof StackAbility) { // sb.append(usedVerb);
Card card = game.getCard(((StackAbility) object).getSourceId()); // }
if (card != null) { // } else if (target.isNotTarget() && (usedVerb == null || usedVerb.equals(" targeting "))) {
sb.append(card.getName()); // usedVerb = " choosing ";
} else { // sb.append(usedVerb);
sb.append(object.getName()); // }
} // sb.append(target.getTargetedName(game));
} else { // }
if (object instanceof Spell) { // }
Spell<?> spell = (Spell<?>) object; // }
String castText = spell.getSpellAbility().toString();
sb.append((castText.startsWith("Cast ") ? castText.substring(5):castText));
if (spell.getFromZone() == Zone.GRAVEYARD) {
sb.append(" from graveyard");
}
sb.append(getOptionalTextSuffix(game, spell));
} else {
sb.append(object.getName());
}
}
} else {
sb.append("unknown");
}
if (object instanceof Spell && ((Spell) object).getSpellAbilities().size() > 1) {
if (((Spell) object).getSpellAbility().getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)) {
Spell<?> spell = (Spell<?>) object;
int i = 0;
for (SpellAbility spellAbility : spell.getSpellAbilities()) {
i++;
String half;
if (i == 1) {
half = " left";
} else {
half = " right";
}
if (spellAbility.getTargets().size() > 0) {
sb.append(half).append(" half targeting ");
for (Target target: spellAbility.getTargets()) {
sb.append(target.getTargetedName(game));
}
}
}
} else {
Spell<?> spell = (Spell<?>) object;
int i = 0;
for (SpellAbility spellAbility : spell.getSpellAbilities()) {
i++;
if ( i > 1) {
sb.append(" splicing ");
if (spellAbility.name.length() > 5 && spellAbility.name.startsWith("Cast ")) {
sb.append(spellAbility.name.substring(5));
} else {
sb.append(spellAbility.name);
}
}
appendTargetDescriptionForLog(sb, spellAbility.getTargets(), game);
}
}
} else if (object instanceof Spell && ((Spell) object).getSpellAbility().getModes().size() > 1) {
Modes spellModes = ((Spell) object).getSpellAbility().getModes();
int item = 0;
for (Mode mode : spellModes.values()) {
item++;
if (spellModes.getSelectedModes().contains(mode.getId())) {
spellModes.setMode(mode);
sb.append(" (mode ").append(item).append(")");
appendTargetDescriptionForLog(sb, getTargets(), game);
}
}
} else {
appendTargetDescriptionForLog(sb, getTargets(), game);
}
for (Choice choice :this.getChoices()) {
sb.append(" - ").append(choice.getMessage()).append(": ").append(choice.getChoice());
}
return sb.toString();
}
private void appendTargetDescriptionForLog(StringBuilder sb, Targets targets, Game game) {
if (targets.size() > 0) {
String usedVerb = null;
for (Target target: targets) {
if (!target.isNotTarget()) {
if (usedVerb == null || usedVerb.equals(" choosing ")) {
usedVerb = " targeting ";
sb.append(usedVerb);
}
} else if (target.isNotTarget() && (usedVerb == null || usedVerb.equals(" targeting "))) {
usedVerb = " choosing ";
sb.append(usedVerb);
}
sb.append(target.getTargetedName(game));
}
}
}
private String getOptionalTextSuffix(Game game, Spell spell) { // private String getOptionalTextSuffix(Game game, Spell spell) {
StringBuilder sb = new StringBuilder(); // StringBuilder sb = new StringBuilder();
for (Ability ability : (Abilities<Ability>) spell.getAbilities()) { // for (Ability ability : (Abilities<Ability>) spell.getAbilities()) {
if (ability instanceof OptionalAdditionalSourceCosts) { // if (ability instanceof OptionalAdditionalSourceCosts) {
sb.append(((OptionalAdditionalSourceCosts) ability).getCastMessageSuffix()); // sb.append(((OptionalAdditionalSourceCosts) ability).getCastMessageSuffix());
} // }
if (ability instanceof AlternativeSourceCosts) { // if (ability instanceof AlternativeSourceCosts) {
sb.append(((AlternativeSourceCosts) ability).getCastMessageSuffix()); // sb.append(((AlternativeSourceCosts) ability).getCastMessageSuffix());
} // }
} // }
return sb.toString(); // return sb.toString();
} // }
public void setMayActivate(TargetController mayActivate) { public void setMayActivate(TargetController mayActivate) {
this.mayActivate = mayActivate; this.mayActivate = mayActivate;

View file

@ -62,8 +62,8 @@ public class PlayLandAbility extends ActivatedAbilityImpl<PlayLandAbility> {
} }
@Override @Override
public String getActivatedMessage(Game game) { public String getGameLogMessage(Game game) {
return " plays " + getMessageText(game); return new StringBuilder(" plays ").append(getMessageText(game)).toString();
} }
@Override @Override

View file

@ -34,6 +34,7 @@ import mage.constants.Zone;
/** /**
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
* @param <T>
*/ */
public abstract class SpecialAction<T extends SpecialAction<T>> extends ActivatedAbilityImpl<T> { public abstract class SpecialAction<T extends SpecialAction<T>> extends ActivatedAbilityImpl<T> {

View file

@ -114,8 +114,8 @@ public class SpellAbility extends ActivatedAbilityImpl<SpellAbility> {
} }
@Override @Override
public String getActivatedMessage(Game game) { public String getGameLogMessage(Game game) {
return " casts " + getMessageText(game); return new StringBuilder(" casts ").append(getMessageText(game)).toString();
} }
@Override @Override

View file

@ -29,10 +29,10 @@
package mage.abilities; package mage.abilities;
import java.util.UUID; import java.util.UUID;
import mage.constants.AbilityType;
import mage.constants.Zone;
import mage.MageObject; import mage.MageObject;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.constants.AbilityType;
import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
@ -95,19 +95,23 @@ public abstract class TriggeredAbilityImpl<T extends TriggeredAbilityImpl<T>> ex
} }
//20091005 - 603.4 //20091005 - 603.4
if (checkInterveningIfClause(game)) { if (checkInterveningIfClause(game)) {
// log resolve of triggered ability
if (object != null && object.getName() != null) {
if (this.getRuleVisible()) {
game.informPlayers(new StringBuilder(object.getName()).append(" triggered ability resolves: ").append(this.getRule(object.getName())).toString());
}
} else {
game.informPlayers(new StringBuilder("Ability triggered: ").append(this.getRule()).toString());
}
return super.resolve(game); return super.resolve(game);
} }
return false; return false;
} }
@Override
public String getGameLogMessage(Game game) {
MageObject object = game.getObject(sourceId);
StringBuilder sb = new StringBuilder();
if (object != null) {
sb.append(object.getName()).append(" - ability triggered: ").append(this.getRule(object.getName()));
} else {
sb.append("Ability triggered: ").append(this.getRule());
}
return sb.toString();
}
@Override @Override
public String getRule() { public String getRule() {
String superRule = super.getRule(true); String superRule = super.getRule(true);

View file

@ -588,7 +588,7 @@ public class GameState implements Serializable, Copyable<GameState> {
} }
public List<TriggeredAbility> getTriggered(UUID controllerId) { public List<TriggeredAbility> getTriggered(UUID controllerId) {
List<TriggeredAbility> triggereds = new ArrayList<TriggeredAbility>(); List<TriggeredAbility> triggereds = new ArrayList<>();
for (TriggeredAbility ability: triggered) { for (TriggeredAbility ability: triggered) {
if (ability.getControllerId().equals(controllerId)) { if (ability.getControllerId().equals(controllerId)) {
triggereds.add(ability); triggereds.add(ability);

View file

@ -69,8 +69,8 @@ import mage.watchers.Watcher;
*/ */
public class Spell<T extends Spell<T>> implements StackObject, Card { public class Spell<T extends Spell<T>> implements StackObject, Card {
private final List<Card> spellCards = new ArrayList<Card>(); private final List<Card> spellCards = new ArrayList<>();
private final List<SpellAbility> spellAbilities = new ArrayList<SpellAbility>(); private final List<SpellAbility> spellAbilities = new ArrayList<>();
private final Card card; private final Card card;
private final SpellAbility ability; private final SpellAbility ability;
@ -144,7 +144,7 @@ public class Spell<T extends Spell<T>> implements StackObject, Card {
} }
public String getActivatedMessage(Game game) { public String getActivatedMessage(Game game) {
return ability.getActivatedMessage(game); return ability.getGameLogMessage(game);
} }
@Override @Override
@ -463,7 +463,7 @@ public class Spell<T extends Spell<T>> implements StackObject, Card {
@Override @Override
public List<CardType> getCardType() { public List<CardType> getCardType() {
if (this.getSpellAbility() instanceof BestowAbility) { if (this.getSpellAbility() instanceof BestowAbility) {
List<CardType> cardTypes = new ArrayList<CardType>(); List<CardType> cardTypes = new ArrayList<>();
cardTypes.addAll(card.getCardType()); cardTypes.addAll(card.getCardType());
cardTypes.remove(CardType.CREATURE); cardTypes.remove(CardType.CREATURE);
return cardTypes; return cardTypes;
@ -474,7 +474,7 @@ public class Spell<T extends Spell<T>> implements StackObject, Card {
@Override @Override
public List<String> getSubtype() { public List<String> getSubtype() {
if (this.getSpellAbility() instanceof BestowAbility) { if (this.getSpellAbility() instanceof BestowAbility) {
List<String> subtypes = new ArrayList<String>(); List<String> subtypes = new ArrayList<>();
subtypes.addAll(card.getSubtype()); subtypes.addAll(card.getSubtype());
subtypes.add("Aura"); subtypes.add("Aura");
return subtypes; return subtypes;

View file

@ -399,6 +399,11 @@ public class StackAbility implements StackObject, Ability {
public void setAbilityWord(AbilityWord abilityWord) { public void setAbilityWord(AbilityWord abilityWord) {
throw new UnsupportedOperationException("Not supported."); throw new UnsupportedOperationException("Not supported.");
} }
@Override
public String getGameLogMessage(Game game) {
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
}
} }

View file

@ -161,7 +161,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
protected boolean quit; protected boolean quit;
protected RangeOfInfluence range; protected RangeOfInfluence range;
protected Set<UUID> inRange = new HashSet<UUID>(); protected Set<UUID> inRange = new HashSet<>();
protected boolean isTestMode = false; protected boolean isTestMode = false;
protected boolean canGainLife = true; protected boolean canGainLife = true;
protected boolean canLoseLife = true; protected boolean canLoseLife = true;
@ -169,8 +169,8 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
protected boolean canPaySacrificeCost = true; protected boolean canPaySacrificeCost = true;
protected boolean isGameUnderControl = true; protected boolean isGameUnderControl = true;
protected UUID turnController; protected UUID turnController;
protected Set<UUID> playersUnderYourControl = new HashSet<UUID>(); protected Set<UUID> playersUnderYourControl = new HashSet<>();
protected List<UUID> attachments = new ArrayList<UUID>(); protected List<UUID> attachments = new ArrayList<>();
protected boolean topCardRevealed = false; protected boolean topCardRevealed = false;
@ -715,7 +715,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
GameEvent event = GameEvent.getEvent(GameEvent.EventType.SPELL_CAST, spell.getSpellAbility().getId(), spell.getSpellAbility().getSourceId(), playerId); GameEvent event = GameEvent.getEvent(GameEvent.EventType.SPELL_CAST, spell.getSpellAbility().getId(), spell.getSpellAbility().getSourceId(), playerId);
event.setZone(fromZone); event.setZone(fromZone);
game.fireEvent(event); game.fireEvent(event);
game.fireInformEvent(new StringBuilder(name).append(spell.getActivatedMessage(game)).toString()); game.informPlayers(new StringBuilder(name).append(spell.getActivatedMessage(game)).toString());
game.removeBookmark(bookmark); game.removeBookmark(bookmark);
resetStoredBookmark(game); resetStoredBookmark(game);
return true; return true;
@ -778,7 +778,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
game.getStack().push(new StackAbility(ability, playerId)); game.getStack().push(new StackAbility(ability, playerId));
if (ability.activate(game, false)) { if (ability.activate(game, false)) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.ACTIVATED_ABILITY, ability.getId(), ability.getSourceId(), playerId)); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.ACTIVATED_ABILITY, ability.getId(), ability.getSourceId(), playerId));
game.fireInformEvent(name + ability.getActivatedMessage(game)); game.informPlayers(new StringBuilder(name).append(ability.getGameLogMessage(game)).toString());
game.removeBookmark(bookmark); game.removeBookmark(bookmark);
resetStoredBookmark(game); resetStoredBookmark(game);
return true; return true;
@ -804,7 +804,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
int bookmark = game.bookmarkState(); int bookmark = game.bookmarkState();
if (action.activate(game, false)) { if (action.activate(game, false)) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.ACTIVATED_ABILITY, action.getSourceId(), action.getId(), playerId)); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.ACTIVATED_ABILITY, action.getSourceId(), action.getId(), playerId));
game.fireInformEvent(name + action.getActivatedMessage(game)); game.informPlayers(new StringBuilder(name).append(action.getGameLogMessage(game)).toString());
if (action.resolve(game)) { if (action.resolve(game)) {
game.removeBookmark(bookmark); game.removeBookmark(bookmark);
resetStoredBookmark(game); resetStoredBookmark(game);
@ -866,23 +866,29 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
//20091005 - 603.3c, 603.3d //20091005 - 603.3c, 603.3d
int bookmark = game.bookmarkState(); int bookmark = game.bookmarkState();
//FIXME: remove try\catch once we find out the reason for NPE on server //FIXME: remove try\catch once we find out the reason for NPE on server
TriggeredAbility ability = null; TriggeredAbility ability = source.copy();
try { // try {
ability = source.copy(); // ability = source.copy();
} catch (NullPointerException npe) { // } catch (NullPointerException npe) {
log.fatal("NPE for source=" + source); // log.fatal("NPE for source=" + source);
log.fatal("NPE for source=" + source.getRule()); // log.fatal("NPE for source=" + source.getRule());
throw npe; // throw npe;
} // }
if (ability != null && ability.canChooseTarget(game)) { if (ability != null && ability.canChooseTarget(game)) {
if (ability.isUsesStack()) { if (ability.isUsesStack()) {
game.getStack().push(new StackAbility(ability, playerId)); game.getStack().push(new StackAbility(ability, playerId));
if (ability.activate(game, false)) { if (ability.activate(game, false)) {
if (ability.getRuleVisible()) {
game.informPlayers(ability.getGameLogMessage(game));
}
game.removeBookmark(bookmark); game.removeBookmark(bookmark);
return true; return true;
} }
} else { } else {
if (ability.activate(game, false)) { if (ability.activate(game, false)) {
if (ability.getRuleVisible()) {
game.informPlayers(ability.getGameLogMessage(game));
}
ability.resolve(game); ability.resolve(game);
game.removeBookmark(bookmark); game.removeBookmark(bookmark);
return true; return true;
@ -894,7 +900,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
} }
protected LinkedHashMap<UUID, ActivatedAbility> getSpellAbilities(MageObject object, Zone zone, Game game) { protected LinkedHashMap<UUID, ActivatedAbility> getSpellAbilities(MageObject object, Zone zone, Game game) {
LinkedHashMap<UUID, ActivatedAbility> useable = new LinkedHashMap<UUID, ActivatedAbility>(); LinkedHashMap<UUID, ActivatedAbility> useable = new LinkedHashMap<>();
for (Ability ability: object.getAbilities()) { for (Ability ability: object.getAbilities()) {
if (ability instanceof SpellAbility) { if (ability instanceof SpellAbility) {
if (((SpellAbility) ability).getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)) { if (((SpellAbility) ability).getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)) {
@ -976,7 +982,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
} }
protected LinkedHashMap<UUID, ManaAbility> getUseableManaAbilities(MageObject object, Zone zone, Game game) { protected LinkedHashMap<UUID, ManaAbility> getUseableManaAbilities(MageObject object, Zone zone, Game game) {
LinkedHashMap<UUID, ManaAbility> useable = new LinkedHashMap<UUID, ManaAbility>(); LinkedHashMap<UUID, ManaAbility> useable = new LinkedHashMap<>();
for (ManaAbility ability: object.getAbilities().getManaAbilities(zone)) { for (ManaAbility ability: object.getAbilities().getManaAbilities(zone)) {
if (ability.canActivate(playerId, game)) { if (ability.canActivate(playerId, game)) {
useable.put(ability.getId(), ability); useable.put(ability.getId(), ability);
@ -1044,14 +1050,14 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
@Override @Override
public void untap(Game game) { public void untap(Game game) {
// create list of all "notMoreThan" effects to track which one are consumed // create list of all "notMoreThan" effects to track which one are consumed
HashMap<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffectsUsage = new HashMap<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer>(); HashMap<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffectsUsage = new HashMap<>();
for (Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>> restrictionEffect: game.getContinuousEffects().getApplicableRestrictionUntapNotMoreThanEffects(this, game).entrySet()) { for (Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>> restrictionEffect: game.getContinuousEffects().getApplicableRestrictionUntapNotMoreThanEffects(this, game).entrySet()) {
notMoreThanEffectsUsage.put(restrictionEffect, new Integer(restrictionEffect.getKey().getNumber())); notMoreThanEffectsUsage.put(restrictionEffect, new Integer(restrictionEffect.getKey().getNumber()));
} }
if (!notMoreThanEffectsUsage.isEmpty()) { if (!notMoreThanEffectsUsage.isEmpty()) {
// create list of all permanents that can be untapped generally // create list of all permanents that can be untapped generally
List<Permanent> canBeUntapped = new ArrayList<Permanent>(); List<Permanent> canBeUntapped = new ArrayList<>();
for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) { for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) {
boolean untap = true; boolean untap = true;
for (RestrictionEffect effect: game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).keySet()) { for (RestrictionEffect effect: game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).keySet()) {
@ -1062,7 +1068,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
} }
} }
// selected permanents to untap // selected permanents to untap
List<Permanent> selectedToUntap = new ArrayList<Permanent>(); List<Permanent> selectedToUntap = new ArrayList<>();
// player can cancel the seletion of an effect to use a prefered order of restriction effects // player can cancel the seletion of an effect to use a prefered order of restriction effects
boolean playerCanceledSelection; boolean playerCanceledSelection;
@ -1173,7 +1179,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
} }
private List<Permanent> getPermanentsThatCanBeUntapped(Game game, List<Permanent> canBeUntapped, RestrictionUntapNotMoreThanEffect handledEffect, HashMap<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffectsUsage) { private List<Permanent> getPermanentsThatCanBeUntapped(Game game, List<Permanent> canBeUntapped, RestrictionUntapNotMoreThanEffect handledEffect, HashMap<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffectsUsage) {
List<Permanent> leftForUntap = new ArrayList<Permanent>(); List<Permanent> leftForUntap = new ArrayList<>();
// select permanents that can still be untapped // select permanents that can still be untapped
for (Permanent permanent: canBeUntapped) { for (Permanent permanent: canBeUntapped) {
if (handledEffect.getFilter().match(permanent, game)) { // matches the restricted permanents of handled entry if (handledEffect.getFilter().match(permanent, game)) { // matches the restricted permanents of handled entry
@ -1698,7 +1704,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
// returns only mana producers that don't require mana payment // returns only mana producers that don't require mana payment
protected List<Permanent> getAvailableManaProducers(Game game) { protected List<Permanent> getAvailableManaProducers(Game game) {
List<Permanent> result = new ArrayList<Permanent>(); List<Permanent> result = new ArrayList<>();
for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) { for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) {
boolean canAdd = false; boolean canAdd = false;
for (ManaAbility ability: permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { for (ManaAbility ability: permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
@ -1719,7 +1725,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
// returns only mana producers that require mana payment // returns only mana producers that require mana payment
protected List<Permanent> getAvailableManaProducersWithCost(Game game) { protected List<Permanent> getAvailableManaProducersWithCost(Game game) {
List<Permanent> result = new ArrayList<Permanent>(); List<Permanent> result = new ArrayList<>();
for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) { for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) {
for (ManaAbility ability: permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { for (ManaAbility ability: permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
if (ability.canActivate(playerId, game) && !ability.getManaCosts().isEmpty()) { if (ability.canActivate(playerId, game) && !ability.getManaCosts().isEmpty()) {
@ -1822,7 +1828,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
} }
} }
// eliminate duplicate activated abilities // eliminate duplicate activated abilities
Map<String, Ability> playableActivated = new HashMap<String, Ability>(); Map<String, Ability> playableActivated = new HashMap<>();
for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) { for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) {
for (ActivatedAbility ability: permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) { for (ActivatedAbility ability: permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) {
if (!playableActivated.containsKey(ability.toString())) { if (!playableActivated.containsKey(ability.toString())) {
@ -1859,7 +1865,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
*/ */
@Override @Override
public List<Ability> getPlayableOptions(Ability ability, Game game) { public List<Ability> getPlayableOptions(Ability ability, Game game) {
List<Ability> options = new ArrayList<Ability>(); List<Ability> options = new ArrayList<>();
if (ability.isModal()) { if (ability.isModal()) {
addModeOptions(options, ability, game); addModeOptions(options, ability, game);