* Fixed attack tap handling - You can no longer attack with a mana producing creature that will be get tapped for attacking and use the creature itself to produce mana to pay for effects like Ghostly Prison if the mana ability has the cost to tap the creature.

This commit is contained in:
LevelX2 2015-04-16 15:57:17 +02:00
parent 28171b3b6a
commit b2fe13c8c8
20 changed files with 224 additions and 234 deletions

View file

@ -347,7 +347,10 @@ public class SimulatedPlayer2 extends ComputerPlayer {
}
for (int j = 0; j < attackersList.size(); j++) {
if (binary.charAt(j) == '1') {
sim.getCombat().declareAttacker(attackersList.get(j).getId(), defenderId, sim);
setStoredBookmark(sim.bookmarkState()); // makes it possible to UNDO a declared attacker with costs from e.g. Propaganda
if(!sim.getCombat().declareAttacker(attackersList.get(j).getId(), defenderId, playerId, sim)) {
sim.undo(playerId);
}
}
}
if (engagements.put(sim.getCombat().getValue().hashCode(), sim.getCombat()) != null) {

View file

@ -187,7 +187,10 @@ public class SimulatedPlayerMCTS extends MCTSPlayer {
}
for (int i = 0; i < attackersList.size(); i++) {
if (binary.charAt(i) == '1') {
game.getCombat().declareAttacker(attackersList.get(i).getId(), defenderId, game);
setStoredBookmark(game.bookmarkState()); // makes it possible to UNDO a declared attacker with costs from e.g. Propaganda
if (!game.getCombat().declareAttacker(attackersList.get(i).getId(), defenderId, playerId, game)) {
game.undo(playerId);
}
}
}
actionCount++;

View file

@ -177,8 +177,12 @@ public class SimulatedPlayer extends ComputerPlayer {
binary.insert(0, "0");
}
for (int j = 0; j < attackersList.size(); j++) {
if (binary.charAt(j) == '1')
sim.getCombat().declareAttacker(attackersList.get(j).getId(), defenderId, sim);
if (binary.charAt(j) == '1') {
setStoredBookmark(sim.bookmarkState()); // makes it possible to UNDO a declared attacker with costs from e.g. Propaganda
if (!sim.getCombat().declareAttacker(attackersList.get(j).getId(), defenderId, playerId, sim)) {
sim.undo(playerId);
}
}
}
if (engagements.put(sim.getCombat().getValue().hashCode(), sim.getCombat()) != null) {
logger.debug("simulating -- found redundant attack combination");

View file

@ -58,7 +58,6 @@ public class FloodtideSerpent extends CardImpl {
this.expansionSetCode = "BNG";
this.subtype.add("Serpent");
this.color.setBlue(true);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
@ -95,11 +94,6 @@ class FloodtideSerpentReplacementEffect extends ReplacementEffectImpl {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player player = game.getPlayer(event.getPlayerId());

View file

@ -80,36 +80,35 @@ class GhostlyPrisonReplacementEffect extends ReplacementEffectImpl {
}
@Override
public boolean apply(Game game, Ability source) {
throw new UnsupportedOperationException("Not supported.");
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
if ( event.getType() == GameEvent.EventType.DECLARE_ATTACKER) {
Player player = game.getPlayer(event.getPlayerId());
if ( player != null && event.getTargetId().equals(source.getControllerId())) {
ManaCostsImpl attackTax = new ManaCostsImpl("{2}");
if ( attackTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
player.chooseUse(Outcome.Benefit, "Pay {2} to attack player?", game) ) {
if (attackTax.payOrRollback(source, game, this.getId(), event.getPlayerId())) {
return false;
}
}
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getTargetId().equals(source.getControllerId()) ) {
Player attackedPlayer = game.getPlayer(event.getTargetId());
if (attackedPlayer != null) {
// only if a player is attacked. Attacking a planeswalker is free
return true;
}
}
return false;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if ( event.getType() == GameEvent.EventType.DECLARE_ATTACKER && event.getTargetId().equals(source.getControllerId()) ) {
Player attackedPlayer = game.getPlayer(event.getTargetId());
if (attackedPlayer != null) {
// only if a player is attacked. Attacking a planeswalker is free
return true;
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player player = game.getPlayer(event.getPlayerId());
if ( player != null && event.getTargetId().equals(source.getControllerId())) {
ManaCostsImpl attackTax = new ManaCostsImpl("{2}");
if (attackTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
player.chooseUse(Outcome.Benefit, "Pay {2} to attack player?", game) ) {
if (attackTax.payOrRollback(source, game, this.getId(), event.getPlayerId())) {
return false;
}
}
return true;
}
return false;
}

View file

@ -159,7 +159,7 @@ class KaaliaOfTheVastEffect extends OneShotEffect {
player.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId(), true);
Permanent creature = game.getPermanent(cardId);
if (creature != null) {
game.getCombat().declareAttacker(card.getId(), defenderId, game);
game.getCombat().addAttackerToCombat(card.getId(), defenderId, game);
return true;
}

View file

@ -65,8 +65,6 @@ public class MysticBarrier extends CardImpl {
super(ownerId, 18, "Mystic Barrier", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{W}");
this.expansionSetCode = "C13";
this.color.setWhite(true);
// When Mystic Barrier enters the battlefield or at the beginning of your upkeep, choose left or right.
this.addAbility(new MysticBarrierTriggeredAbility());
@ -98,16 +96,19 @@ class MysticBarrierTriggeredAbility extends TriggeredAbilityImpl {
public MysticBarrierTriggeredAbility copy() {
return new MysticBarrierTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType().equals(EventType.ENTERS_THE_BATTLEFIELD) || event.getType().equals(EventType.UPKEEP_STEP_PRE);
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getType().equals(EventType.ENTERS_THE_BATTLEFIELD) && event.getTargetId().equals(this.getSourceId())) {
return true;
if (event.getType().equals(EventType.ENTERS_THE_BATTLEFIELD)) {
return event.getTargetId().equals(this.getSourceId());
} else {
return event.getPlayerId().equals(this.getControllerId());
}
if (event.getType().equals(EventType.UPKEEP_STEP_PRE) && event.getPlayerId().equals(this.getControllerId())) {
return true;
}
return false;
}
@Override
@ -170,19 +171,19 @@ class MysticBarrierReplacementEffect extends ReplacementEffectImpl {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
return true;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if ( event.getType() == GameEvent.EventType.DECLARE_ATTACKER && game.getPlayers().size() > 2) {
if (game.getPlayers().size() > 2) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
if (controller.getInRange().contains(event.getPlayerId())) {

View file

@ -64,7 +64,6 @@ public class EvilEyeOfOrmsByGore extends CardImpl {
this.expansionSetCode = "5ED";
this.subtype.add("Eye");
this.color.setBlack(true);
this.power = new MageInt(3);
this.toughness = new MageInt(6);
@ -96,33 +95,31 @@ class EvilEyeOfOrmsByGoreEffect extends ReplacementEffectImpl {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public EvilEyeOfOrmsByGoreEffect copy() {
return new EvilEyeOfOrmsByGoreEffect(this);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
return true;
}
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() == EventType.DECLARE_ATTACKER) {
Permanent permanent = game.getPermanent(event.getSourceId());
if (permanent != null) {
if (permanent.getControllerId().equals(source.getControllerId())) {
if (!permanent.hasSubtype("Eye")) {
return true;
}
Permanent permanent = game.getPermanent(event.getSourceId());
if (permanent != null) {
if (permanent.getControllerId().equals(source.getControllerId())) {
if (!permanent.hasSubtype("Eye")) {
return true;
}
}
}
return false;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
return true;
}
}

View file

@ -61,7 +61,6 @@ public class OrissSamiteGuardian extends CardImpl {
this.subtype.add("Human");
this.subtype.add("Cleric");
this.color.setWhite(true);
this.power = new MageInt(1);
this.toughness = new MageInt(3);
@ -104,19 +103,14 @@ class OrissSamiteGuardianCantCastEffect extends ContinuousRuleModifyingEffectImp
}
@Override
public boolean apply(Game game, Ability source) {
return true;
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.CAST_SPELL;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() == EventType.CAST_SPELL) {
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player != null && player.getId().equals(event.getPlayerId())) {
return true;
}
}
return false;
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
return player != null && player.getId().equals(event.getPlayerId());
}
}
@ -135,20 +129,15 @@ class OrissSamiteGuardianCantAttackEffect extends ContinuousRuleModifyingEffectI
public OrissSamiteGuardianCantAttackEffect copy() {
return new OrissSamiteGuardianCantAttackEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() == EventType.DECLARE_ATTACKER) {
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player != null && player.getId().equals(event.getPlayerId())) {
return true;
}
}
return false;
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
return player != null && player.getId().equals(event.getPlayerId());
}
}

View file

@ -79,30 +79,12 @@ class NornsAnnexReplacementEffect extends ReplacementEffectImpl {
NornsAnnexReplacementEffect(NornsAnnexReplacementEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
throw new UnsupportedOperationException("Not supported.");
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
if (event.getType() == GameEvent.EventType.DECLARE_ATTACKER) {
Player player = game.getPlayer(event.getPlayerId());
if (player != null && event.getTargetId().equals(source.getControllerId())) {
ManaCostsImpl propagandaTax = new ManaCostsImpl("{WP}");
if (propagandaTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
player.chooseUse(Outcome.Benefit, "Pay {WP} to declare attacker?", game)) {
if (propagandaTax.payOrRollback(source, game, this.getId(), event.getPlayerId())) {
return false;
}
}
}
return true;
}
return false;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() == GameEvent.EventType.DECLARE_ATTACKER) {
@ -119,6 +101,24 @@ class NornsAnnexReplacementEffect extends ReplacementEffectImpl {
return false;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player player = game.getPlayer(event.getPlayerId());
if (player != null && event.getTargetId().equals(source.getControllerId())) {
ManaCostsImpl propagandaTax = new ManaCostsImpl("{WP}");
if (propagandaTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
player.chooseUse(Outcome.Benefit, "Pay {WP} to declare attacker?", game)) {
if (propagandaTax.payOrRollback(source, game, this.getId(), event.getPlayerId())) {
return false;
}
}
return true;
}
return false;
}
@Override
public NornsAnnexReplacementEffect copy() {
return new NornsAnnexReplacementEffect(this);

View file

@ -54,8 +54,6 @@ public class SphereOfSafety extends CardImpl {
super(ownerId, 24, "Sphere of Safety", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{4}{W}");
this.expansionSetCode = "RTR";
this.color.setWhite(true);
// Creatures can't attack you or a planeswalker you control unless their controller pays {X} for each of those creatures, where X is the number of enchantments you control.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SphereOfSafetyReplacementEffect()));
@ -79,7 +77,7 @@ class SphereOfSafetyReplacementEffect extends ReplacementEffectImpl {
static {
filter.add(new ControllerPredicate(TargetController.YOU));
}
private PermanentsOnBattlefieldCount countEnchantments = new PermanentsOnBattlefieldCount(filter);
private final PermanentsOnBattlefieldCount countEnchantments = new PermanentsOnBattlefieldCount(filter);
SphereOfSafetyReplacementEffect ( ) {
@ -90,51 +88,46 @@ class SphereOfSafetyReplacementEffect extends ReplacementEffectImpl {
SphereOfSafetyReplacementEffect ( SphereOfSafetyReplacementEffect effect ) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
throw new UnsupportedOperationException("Not supported.");
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
if ( event.getType() == GameEvent.EventType.DECLARE_ATTACKER) {
Player player = game.getPlayer(event.getPlayerId());
if ( player != null ) {
int ce = countEnchantments.calculate(game, source, this);
ManaCostsImpl safetyCosts = new ManaCostsImpl("{"+ ce +"}");
if ( safetyCosts.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
player.chooseUse(Outcome.Benefit, "Pay {"+ ce +"} to declare attacker?", game) )
{
if (safetyCosts.payOrRollback(source, game, this.getId(), event.getPlayerId())) {
return false;
}
}
}
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getTargetId().equals(source.getControllerId()) ) {
return true;
}
// planeswalker
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null && permanent.getControllerId().equals(source.getControllerId())
&& permanent.getCardType().contains(CardType.PLANESWALKER)) {
return true;
}
return false;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if ( event.getType() == GameEvent.EventType.DECLARE_ATTACKER) {
if (event.getTargetId().equals(source.getControllerId()) ) {
return true;
}
// planeswalker
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null && permanent.getControllerId().equals(source.getControllerId())
&& permanent.getCardType().contains(CardType.PLANESWALKER)) {
return true;
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player player = game.getPlayer(event.getPlayerId());
if ( player != null ) {
int ce = countEnchantments.calculate(game, source, this);
ManaCostsImpl safetyCosts = new ManaCostsImpl("{"+ ce +"}");
if ( safetyCosts.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
player.chooseUse(Outcome.Benefit, "Pay {"+ ce +"} to declare attacker?", game) ) {
if (safetyCosts.payOrRollback(source, game, this.getId(), event.getPlayerId())) {
return false;
}
}
return true;
}
return false;
}
@Override
public SphereOfSafetyReplacementEffect copy() {
return new SphereOfSafetyReplacementEffect(this);
}
}
}

View file

@ -97,6 +97,17 @@ class CowedByWisdomEffect extends ReplacementEffectImpl {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARE_ATTACKER || event.getType().equals(GameEvent.EventType.DECLARE_BLOCKER);
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
Permanent enchantment = game.getPermanent(event.getSourceId());
return enchantment != null && enchantment.getAttachments().contains(source.getSourceId());
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player player = game.getPlayer(event.getPlayerId());
@ -123,20 +134,7 @@ class CowedByWisdomEffect extends ReplacementEffectImpl {
}
return false;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType().equals(GameEvent.EventType.DECLARE_ATTACKER)) {
Permanent attacker = game.getPermanent(event.getSourceId());
return attacker != null && attacker.getAttachments().contains(source.getSourceId());
}
if (event.getType().equals(GameEvent.EventType.DECLARE_BLOCKER)) {
Permanent blocker = game.getPermanent(event.getSourceId());
return blocker != null && blocker.getAttachments().contains(source.getSourceId());
}
return false;
}
@Override
public CowedByWisdomEffect copy() {
return new CowedByWisdomEffect(this);

View file

@ -81,33 +81,32 @@ class LightOfDayEffect extends ReplacementEffectImpl {
}
@Override
public boolean apply(Game game, Ability source) {
return true;
public LightOfDayEffect copy() {
return new LightOfDayEffect(this);
}
@Override
public LightOfDayEffect copy() {
return new LightOfDayEffect(this);
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.DECLARE_ATTACKER || event.getType() == EventType.DECLARE_BLOCKER;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
Permanent permanent = game.getPermanent(event.getSourceId());
if (permanent != null) {
Player player = game.getPlayer(source.getControllerId());
if (player.getInRange().contains(permanent.getControllerId())) {
if (permanent.getColor().isBlack()) {
return true;
}
}
}
return false;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
return true;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() == EventType.DECLARE_ATTACKER || event.getType() == EventType.DECLARE_BLOCKER) {
Permanent permanent = game.getPermanent(event.getSourceId());
if (permanent != null) {
Player player = game.getPlayer(source.getControllerId());
if (player.getInRange().contains(permanent.getControllerId())) {
if (permanent.getColor().isBlack()) {
return true;
}
}
}
}
return false;
}
}

View file

@ -81,8 +81,20 @@ class PropagandaReplacementEffect extends ReplacementEffectImpl {
}
@Override
public boolean apply(Game game, Ability source) {
throw new UnsupportedOperationException("Not supported.");
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getTargetId().equals(source.getControllerId())) {
Player attackedPlayer = game.getPlayer(event.getTargetId());
if (attackedPlayer != null) {
// only if a player is attacked. Attacking a planeswalker is free
return true;
}
}
return false;
}
@Override
@ -101,19 +113,7 @@ class PropagandaReplacementEffect extends ReplacementEffectImpl {
}
return false;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if ( event.getType() == GameEvent.EventType.DECLARE_ATTACKER && event.getTargetId().equals(source.getControllerId())) {
Player attackedPlayer = game.getPlayer(event.getTargetId());
if (attackedPlayer != null) {
// only if a player is attacked. Attacking a planeswalker is free
return true;
}
}
return false;
}
@Override
public PropagandaReplacementEffect copy() {
return new PropagandaReplacementEffect(this);

View file

@ -51,7 +51,6 @@ public class WindbornMuse extends CardImpl {
super(ownerId, 60, "Windborn Muse", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{W}");
this.expansionSetCode = "10E";
this.subtype.add("Spirit");
this.color.setWhite(true);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
@ -86,32 +85,13 @@ class WindbornMuseReplacementEffect extends ReplacementEffectImpl {
}
@Override
public boolean apply(Game game, Ability source) {
throw new UnsupportedOperationException("Not supported.");
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
if ( event.getType() == GameEvent.EventType.DECLARE_ATTACKER) {
Player player = game.getPlayer(event.getPlayerId());
if ( player != null && event.getTargetId().equals(source.getControllerId())) {
ManaCostsImpl attackTax = new ManaCostsImpl("{2}");
if ( attackTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
player.chooseUse(Outcome.Benefit, "Pay {2} to attack player?", game) )
{
if (attackTax.payOrRollback(source, game, this.getId(), event.getPlayerId())) {
return false;
}
}
}
return true;
}
return false;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if ( event.getType() == GameEvent.EventType.DECLARE_ATTACKER && event.getTargetId().equals(source.getControllerId()) ) {
if (event.getTargetId().equals(source.getControllerId()) ) {
Player attackedPlayer = game.getPlayer(event.getTargetId());
if (attackedPlayer != null) {
// only if a player is attacked. Attacking a planeswalker is free
@ -120,6 +100,23 @@ class WindbornMuseReplacementEffect extends ReplacementEffectImpl {
}
return false;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player player = game.getPlayer(event.getPlayerId());
if ( player != null && event.getTargetId().equals(source.getControllerId())) {
ManaCostsImpl attackTax = new ManaCostsImpl("{2}");
if ( attackTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
player.chooseUse(Outcome.Benefit, "Pay {2} to attack player?", game) )
{
if (attackTax.payOrRollback(source, game, this.getId(), event.getPlayerId())) {
return false;
}
}
return true;
}
return false;
}
@Override
public WindbornMuseReplacementEffect copy() {

View file

@ -51,8 +51,6 @@ public class ElephantGrass extends CardImpl {
super(ownerId, 54, "Elephant Grass", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{G}");
this.expansionSetCode = "VIS";
this.color.setGreen(true);
// Cumulative upkeep {1}
this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl("{1}")));
// Black creatures can't attack you.
@ -85,18 +83,13 @@ class ElephantGrassReplacementEffect extends ReplacementEffectImpl {
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
return true;
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if ( event.getType() == GameEvent.EventType.DECLARE_ATTACKER && event.getTargetId().equals(source.getControllerId()) ) {
if (event.getTargetId().equals(source.getControllerId()) ) {
Permanent creature = game.getPermanent(event.getSourceId());
if(creature != null && creature.getColor().isBlack()){
return true;
@ -105,6 +98,12 @@ class ElephantGrassReplacementEffect extends ReplacementEffectImpl {
return false;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
return true;
}
@Override
public ElephantGrassReplacementEffect copy() {
return new ElephantGrassReplacementEffect(this);

View file

@ -190,9 +190,13 @@ public class RandomPlayer extends ComputerPlayer {
binary.insert(0, "0"); //pad with zeros
}
for (int i = 0; i < attackersList.size(); i++) {
if (binary.charAt(i) == '1')
game.getCombat().declareAttacker(attackersList.get(i).getId(), defenderId, game);
}
if (binary.charAt(i) == '1') {
setStoredBookmark(game.bookmarkState()); // makes it possible to UNDO a declared attacker with costs from e.g. Propaganda
if (!game.getCombat().declareAttacker(attackersList.get(i).getId(), defenderId, playerId, game)) {
game.undo(playerId);
}
}
}
actionCount++;
}

View file

@ -134,7 +134,7 @@ class NinjutsuEffect extends OneShotEffect {
}
}
if (defendingPlayerId != null) {
game.getCombat().declareAttacker(permanent.getId(), defendingPlayerId, game);
game.getCombat().addAttackerToCombat(permanent.getId(), defendingPlayerId, game);
permanent.setTapped(true);
return true;
}

View file

@ -182,6 +182,7 @@ public class Combat implements Serializable, Copyable<Combat> {
/**
* Add an additional attacker to the combat (e.g. token of Geist of Saint
* Traft) This method doesn't trigger ATTACKER_DECLARED event (as intended).
* If the creature has to be tapped that won't do this method.
*
* @param creatureId - creature that shall be added to the combat
* @param game
@ -190,14 +191,14 @@ public class Combat implements Serializable, Copyable<Combat> {
public boolean addAttackingCreature(UUID creatureId, Game game) {
Player player = game.getPlayer(attackerId);
if (defenders.size() == 1) {
declareAttacker(creatureId, defenders.iterator().next(), game);
addAttackerToCombat(creatureId, defenders.iterator().next(), game);
return true;
} else {
TargetDefender target = new TargetDefender(defenders, creatureId);
target.setRequired(true);
player.chooseTarget(Outcome.Damage, target, null, game);
if (target.getFirstTarget() != null) {
declareAttacker(creatureId, target.getFirstTarget(), game);
addAttackerToCombat(creatureId, target.getFirstTarget(), game);
return true;
}
}
@ -844,7 +845,20 @@ public class Combat implements Serializable, Copyable<Combat> {
}
}
public boolean declareAttacker(UUID attackerId, UUID defenderId, Game game) {
public boolean declareAttacker(UUID attackerId, UUID defenderId, UUID playerId, Game game) {
Permanent attacker = game.getPermanent(attackerId);
if (!attacker.getAbilities().containsKey(VigilanceAbility.getInstance().getId())) {
if (!attacker.isTapped()) {
attacker.tap(game);
}
}
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_ATTACKER, defenderId, attackerId, playerId))) {
return addAttackerToCombat(attackerId, defenderId, game);
}
return false;
}
public boolean addAttackerToCombat(UUID attackerId, UUID defenderId, Game game) {
if (!defenders.contains(defenderId)) {
return false;
}
@ -853,16 +867,12 @@ public class Combat implements Serializable, Copyable<Combat> {
if (!canDefenderBeAttacked(attackerId, defenderId, game)) {
return false;
}
CombatGroup newGroup = new CombatGroup(defenderId, defender != null, defender != null ? defender.getControllerId() : defenderId);
newGroup.attackers.add(attackerId);
Permanent attacker = game.getPermanent(attackerId);
if (!attacker.getAbilities().containsKey(VigilanceAbility.getInstance().getId())) {
attacker.tap(game);
}
attacker.setAttacking(true);
groups.add(newGroup);
return true;
return true;
}
public boolean canDefenderBeAttacked(UUID attackerId, UUID defenderId, Game game) {

View file

@ -1989,8 +1989,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
Permanent attacker = game.getPermanent(attackerId);
if (attacker != null && attacker.canAttack(defenderId, game) && attacker.getControllerId().equals(playerId)) {
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_ATTACKER, defenderId, attackerId, playerId))) {
game.getCombat().declareAttacker(attackerId, defenderId, game);
if(!game.getCombat().declareAttacker(attackerId, defenderId, playerId, game)) {
game.undo(playerId);
}
}
}