mirror of
https://github.com/correl/mage.git
synced 2024-11-28 11:09:54 +00:00
* Fixed that creatures that have to pay costs to block were wrongly forced to block causing UI locks.
This commit is contained in:
parent
3868066e00
commit
0a0cb40783
7 changed files with 112 additions and 6 deletions
|
@ -76,7 +76,10 @@ public class HelperPanel extends JPanel {
|
|||
setOpaque(false);
|
||||
|
||||
JPanel container = new JPanel();
|
||||
|
||||
container.setPreferredSize(new Dimension(100, 30));
|
||||
container.setMinimumSize(new Dimension(20, 20));
|
||||
container.setMaximumSize(new Dimension(2000, 100));
|
||||
container.setLayout(new GridBagLayout());
|
||||
container.setOpaque(false);
|
||||
|
||||
|
|
|
@ -964,7 +964,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
protected void selectCombatGroup(UUID defenderId, UUID blockerId, Game game) {
|
||||
updateGameStatePriority("selectCombatGroup", game);
|
||||
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);
|
||||
if (response.getBoolean() != null) {
|
||||
// do nothing
|
||||
|
|
|
@ -69,7 +69,7 @@ public class OppressiveRays extends CardImpl {
|
|||
Ability ability = new EnchantAbility(auraTarget.getTargetName());
|
||||
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)));
|
||||
|
||||
// Activated abilities of enchanted creature cost {3} more to activate.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -47,9 +47,9 @@ public class CantAttackBlockUnlessPaysAttachedEffect extends PayCostToAttackBloc
|
|||
|
||||
public CantAttackBlockUnlessPaysAttachedEffect(ManaCosts manaCosts, AttachmentType attachmentType) {
|
||||
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 "
|
||||
+ manaCosts == null ? "" : manaCosts.getText();
|
||||
+ (manaCosts == null ? "" : manaCosts.getText());
|
||||
}
|
||||
|
||||
public CantAttackBlockUnlessPaysAttachedEffect(CantAttackBlockUnlessPaysAttachedEffect effect) {
|
||||
|
|
|
@ -263,7 +263,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
}
|
||||
}
|
||||
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<>();
|
||||
defendersCostlessAttackable.addAll(defenders);
|
||||
for (UUID defenderId : defenders) {
|
||||
|
@ -501,6 +501,12 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
UUID attackingCreatureId = requirementEntry.getKey().mustBlockAttacker(ability, game);
|
||||
Player defender = game.getPlayer(possibleBlocker.getControllerId());
|
||||
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())) {
|
||||
creatureMustBlockAttackers.get(possibleBlocker.getId()).add(attackingCreatureId);
|
||||
} else {
|
||||
|
@ -734,6 +740,21 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
if (creatureForcedToBlock == null) {
|
||||
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
|
||||
if (creatureForcedToBlock.getBlocking() == 0) {
|
||||
blockIsValid = false;
|
||||
|
@ -765,7 +786,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
|
||||
}
|
||||
if (!blockIsValid) {
|
||||
sb.append(" ").append(creatureForcedToBlock.getLogName());
|
||||
sb.append(" ").append(creatureForcedToBlock.getIdName());
|
||||
}
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
|
|
|
@ -2043,6 +2043,9 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public void declareBlocker(UUID defenderId, UUID blockerId, UUID attackerId, Game game) {
|
||||
if (isHuman()) {
|
||||
setStoredBookmark(game.bookmarkState());
|
||||
}
|
||||
Permanent blocker = game.getPermanent(blockerId);
|
||||
CombatGroup group = game.getCombat().findGroup(attackerId);
|
||||
if (blocker != null && group != null && group.canBlock(blocker, game)) {
|
||||
|
|
Loading…
Reference in a new issue