* Fixed that creatures that have to pay costs to block were wrongly forced to block causing UI locks.

This commit is contained in:
LevelX2 2015-07-01 23:00:22 +02:00
parent 3868066e00
commit 0a0cb40783
7 changed files with 112 additions and 6 deletions

View file

@ -76,7 +76,10 @@ public class HelperPanel extends JPanel {
setOpaque(false); setOpaque(false);
JPanel container = new JPanel(); JPanel container = new JPanel();
container.setPreferredSize(new Dimension(100, 30)); container.setPreferredSize(new Dimension(100, 30));
container.setMinimumSize(new Dimension(20, 20));
container.setMaximumSize(new Dimension(2000, 100));
container.setLayout(new GridBagLayout()); container.setLayout(new GridBagLayout());
container.setOpaque(false); container.setOpaque(false);

View file

@ -964,7 +964,7 @@ public class HumanPlayer extends PlayerImpl {
protected void selectCombatGroup(UUID defenderId, UUID blockerId, Game game) { protected void selectCombatGroup(UUID defenderId, UUID blockerId, Game game) {
updateGameStatePriority("selectCombatGroup", game); updateGameStatePriority("selectCombatGroup", game);
TargetAttackingCreature target = new TargetAttackingCreature(); TargetAttackingCreature target = new TargetAttackingCreature();
game.fireSelectTargetEvent(playerId, "Select attacker to block", target.possibleTargets(null, playerId, game), false, getOptions(target, null)); game.fireSelectTargetEvent(playerId, addSecondLineWithObjectName("Select attacker to block", blockerId, game), target.possibleTargets(null, playerId, game), false, getOptions(target, null));
waitForResponse(game); waitForResponse(game);
if (response.getBoolean() != null) { if (response.getBoolean() != null) {
// do nothing // do nothing

View file

@ -69,7 +69,7 @@ public class OppressiveRays extends CardImpl {
Ability ability = new EnchantAbility(auraTarget.getTargetName()); Ability ability = new EnchantAbility(auraTarget.getTargetName());
this.addAbility(ability); this.addAbility(ability);
// Enchanted creature can't attack or block unless its controller pays 3. // Enchanted creature can't attack or block unless its controller pays {3}.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackBlockUnlessPaysAttachedEffect(new ManaCostsImpl<>("{3}"), AttachmentType.AURA))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackBlockUnlessPaysAttachedEffect(new ManaCostsImpl<>("{3}"), AttachmentType.AURA)));
// Activated abilities of enchanted creature cost {3} more to activate. // Activated abilities of enchanted creature cost {3} more to activate.

View file

@ -0,0 +1,79 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package org.mage.test.cards.requirement;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class BlockRequirementTest extends CardTestPlayerBase {
@Test
public void testPrizedUnicorn() {
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); // 2/2
// All creatures able to block Prized Unicorn do so.
addCard(Zone.BATTLEFIELD, playerB, "Prized Unicorn"); // 2/2
// Silvercoat Lion should be forced to block
attack(2, playerB, "Prized Unicorn");
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertGraveyardCount(playerA, "Silvercoat Lion", 1);
assertGraveyardCount(playerB, "Prized Unicorn", 1);
}
@Test
public void testPrizedUnicornAndOppressiveRays() {
addCard(Zone.BATTLEFIELD, playerA, "Plains");
addCard(Zone.HAND, playerA, "Oppressive Rays");
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); // 2/2
// All creatures able to block Prized Unicorn do so.
addCard(Zone.BATTLEFIELD, playerB, "Prized Unicorn"); // 2/2
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Oppressive Rays", "Silvercoat Lion");
// Silvercoat Lion has not to block because it has to pay {3} to block
attack(2, playerB, "Prized Unicorn");
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertPermanentCount(playerA, "Oppressive Rays", 1);
assertPermanentCount(playerA, "Silvercoat Lion", 1);
assertPermanentCount(playerB, "Prized Unicorn", 1);
}
}

View file

@ -47,9 +47,9 @@ public class CantAttackBlockUnlessPaysAttachedEffect extends PayCostToAttackBloc
public CantAttackBlockUnlessPaysAttachedEffect(ManaCosts manaCosts, AttachmentType attachmentType) { public CantAttackBlockUnlessPaysAttachedEffect(ManaCosts manaCosts, AttachmentType attachmentType) {
super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK_AND_BLOCK, manaCosts); super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK_AND_BLOCK, manaCosts);
staticText = attachmentType.equals(AttachmentType.AURA) ? "Enchanted " : "Equipped " staticText = (attachmentType.equals(AttachmentType.AURA) ? "Enchanted " : "Equipped ")
+ "creature can't attack or block unless its controller pays " + "creature can't attack or block unless its controller pays "
+ manaCosts == null ? "" : manaCosts.getText(); + (manaCosts == null ? "" : manaCosts.getText());
} }
public CantAttackBlockUnlessPaysAttachedEffect(CantAttackBlockUnlessPaysAttachedEffect effect) { public CantAttackBlockUnlessPaysAttachedEffect(CantAttackBlockUnlessPaysAttachedEffect effect) {

View file

@ -263,7 +263,7 @@ public class Combat implements Serializable, Copyable<Combat> {
} }
} }
if (mustAttack) { if (mustAttack) {
// check which defenders the forced to attck creature can attack without paying a cost // check which defenders the forced to attack creature can attack without paying a cost
HashSet<UUID> defendersCostlessAttackable = new HashSet<>(); HashSet<UUID> defendersCostlessAttackable = new HashSet<>();
defendersCostlessAttackable.addAll(defenders); defendersCostlessAttackable.addAll(defenders);
for (UUID defenderId : defenders) { for (UUID defenderId : defenders) {
@ -501,6 +501,12 @@ public class Combat implements Serializable, Copyable<Combat> {
UUID attackingCreatureId = requirementEntry.getKey().mustBlockAttacker(ability, game); UUID attackingCreatureId = requirementEntry.getKey().mustBlockAttacker(ability, game);
Player defender = game.getPlayer(possibleBlocker.getControllerId()); Player defender = game.getPlayer(possibleBlocker.getControllerId());
if (attackingCreatureId != null && defender != null && possibleBlocker.canBlock(attackingCreatureId, game)) { if (attackingCreatureId != null && defender != null && possibleBlocker.canBlock(attackingCreatureId, game)) {
// check if the possible blocker has to pay cost to block, if so don't force
if (game.getContinuousEffects().checkIfThereArePayCostToAttackBlockEffects(
GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKER, attackingCreatureId, possibleBlocker.getId(), possibleBlocker.getControllerId()), game)) {
// has cost to block to pay so remove this attacker
continue;
}
if (creatureMustBlockAttackers.containsKey(possibleBlocker.getId())) { if (creatureMustBlockAttackers.containsKey(possibleBlocker.getId())) {
creatureMustBlockAttackers.get(possibleBlocker.getId()).add(attackingCreatureId); creatureMustBlockAttackers.get(possibleBlocker.getId()).add(attackingCreatureId);
} else { } else {
@ -734,6 +740,21 @@ public class Combat implements Serializable, Copyable<Combat> {
if (creatureForcedToBlock == null) { if (creatureForcedToBlock == null) {
break; break;
} }
// // check if creature has to pay a cost to block so it's not mandatory to block
// boolean removedAttacker = false;
// for (Iterator<UUID> iterator = entry.getValue().iterator(); iterator.hasNext();) {
// UUID possibleAttackerId = iterator.next();
// if (game.getContinuousEffects().checkIfThereArePayCostToAttackBlockEffects(
// GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKER, possibleAttackerId, creatureForcedToBlock.getId(), creatureForcedToBlock.getControllerId()), game)) {
// // has cost to block to pay so remove this attacker
// iterator.remove();
// removedAttacker = true;
// }
// }
// if (removedAttacker && entry.getValue().isEmpty()) {
// continue;
// }
// creature does not block -> not allowed // creature does not block -> not allowed
if (creatureForcedToBlock.getBlocking() == 0) { if (creatureForcedToBlock.getBlocking() == 0) {
blockIsValid = false; blockIsValid = false;
@ -765,7 +786,7 @@ public class Combat implements Serializable, Copyable<Combat> {
} }
if (!blockIsValid) { if (!blockIsValid) {
sb.append(" ").append(creatureForcedToBlock.getLogName()); sb.append(" ").append(creatureForcedToBlock.getIdName());
} }
} }
if (sb.length() > 0) { if (sb.length() > 0) {

View file

@ -2043,6 +2043,9 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public void declareBlocker(UUID defenderId, UUID blockerId, UUID attackerId, Game game) { public void declareBlocker(UUID defenderId, UUID blockerId, UUID attackerId, Game game) {
if (isHuman()) {
setStoredBookmark(game.bookmarkState());
}
Permanent blocker = game.getPermanent(blockerId); Permanent blocker = game.getPermanent(blockerId);
CombatGroup group = game.getCombat().findGroup(attackerId); CombatGroup group = game.getCombat().findGroup(attackerId);
if (blocker != null && group != null && group.canBlock(blocker, game)) { if (blocker != null && group != null && group.canBlock(blocker, game)) {