mirror of
https://github.com/magefree/mage.git
synced 2025-12-24 20:41:58 -08:00
- Fix for Bug #5435. Specific to "must attack" code.
This commit is contained in:
parent
7c2738cf9f
commit
c7a3e53083
3 changed files with 46 additions and 29 deletions
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.game.combat;
|
||||
|
||||
import mage.MageObject;
|
||||
|
|
@ -108,8 +107,8 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get all possible defender (players and plainwalkers) That does not mean
|
||||
* neccessarly mean that they are really attacked
|
||||
* Get all possible defender (players and planeswalkers) That does not mean
|
||||
* necessarily mean that they are really attacked
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
|
@ -251,11 +250,14 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
game.getCombat().checkAttackRequirements(player, game);
|
||||
boolean firstTime = true;
|
||||
do {
|
||||
if (!firstTime || !game.getPlayer(game.getActivePlayerId()).getAvailableAttackers(game).isEmpty()) {
|
||||
if (!firstTime
|
||||
|| !game.getPlayer(game.getActivePlayerId()).getAvailableAttackers(game).isEmpty()) {
|
||||
player.selectAttackers(game, attackingPlayerId);
|
||||
}
|
||||
firstTime = false;
|
||||
if (game.isPaused() || game.checkIfGameIsOver() || game.executingRollback()) {
|
||||
if (game.isPaused()
|
||||
|| game.checkIfGameIsOver()
|
||||
|| game.executingRollback()) {
|
||||
return;
|
||||
}
|
||||
// because of possible undo during declare attackers it's neccassary to call here the methods with "game.getCombat()." to get the current combat object!!!
|
||||
|
|
@ -338,7 +340,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
|| !player.chooseUse(Outcome.Benefit, "Do you wish to " + (isBanded ? "band " + attacker.getLogName() + " with another " : "form a band with " + attacker.getLogName() + " and an ") + "attacking creature?", null, game)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (canBand && canBandWithOther) {
|
||||
if (player.chooseUse(Outcome.Detriment, "Choose type of banding ability to apply:", attacker.getLogName(), "Banding", "Bands with other", null, game)) {
|
||||
canBandWithOther = false;
|
||||
|
|
@ -359,13 +361,13 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
filter.add(Predicates.or(predicates));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (target.choose(Outcome.Benefit, attackingPlayerId, null, game)) {
|
||||
isBanded = true;
|
||||
for (UUID targetId : target.getTargets()) {
|
||||
Permanent permanent = game.getPermanent(targetId);
|
||||
if (permanent != null) {
|
||||
|
||||
|
||||
for (UUID bandedId : attacker.getBandedCards()) {
|
||||
permanent.addBandedCard(bandedId);
|
||||
Permanent banded = game.getPermanent(bandedId);
|
||||
|
|
@ -391,7 +393,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
canBand = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -454,11 +456,16 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
if (defenders.size() == 1) {
|
||||
player.declareAttacker(creature.getId(), defenders.iterator().next(), game, false);
|
||||
} else {
|
||||
TargetDefender target = new TargetDefender(defenders, creature.getId());
|
||||
target.setRequired(true);
|
||||
target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack");
|
||||
if (player.chooseTarget(Outcome.Damage, target, null, game)) {
|
||||
player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false);
|
||||
if (!player.isHuman()) { // computer only for multiple defenders
|
||||
player.declareAttacker(creature.getId(), defenders.iterator().next(), game, false);
|
||||
} else { // human players only for multiple defenders
|
||||
TargetDefender target = new TargetDefender(defenders, creature.getId());
|
||||
target.setRequired(true);
|
||||
target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack");
|
||||
if (player.chooseTarget(Outcome.Damage, target, null, game)) {
|
||||
System.out.println("The player " + player.getName() + " declares an attacker here. " + creature.getName());
|
||||
player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -550,7 +557,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
* Handle the blocker selection process
|
||||
*
|
||||
* @param blockController player that controlls how to block, if null the
|
||||
* defender is the controller
|
||||
* defender is the controller
|
||||
* @param game
|
||||
*/
|
||||
public void selectBlockers(Player blockController, Game game) {
|
||||
|
|
@ -1342,10 +1349,10 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
if (defenderAttackedBy.size() >= defendingPlayer.getMaxAttackedBy()) {
|
||||
Player attackingPlayer = game.getPlayer(game.getControllerId(attackerId));
|
||||
if (attackingPlayer != null && !game.isSimulation()) {
|
||||
game.informPlayer(attackingPlayer, "No more than " +
|
||||
CardUtil.numberToText(defendingPlayer.getMaxAttackedBy()) +
|
||||
" creatures can attack " +
|
||||
defendingPlayer.getLogName());
|
||||
game.informPlayer(attackingPlayer, "No more than "
|
||||
+ CardUtil.numberToText(defendingPlayer.getMaxAttackedBy())
|
||||
+ " creatures can attack "
|
||||
+ defendingPlayer.getLogName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1375,7 +1382,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
* @param playerId
|
||||
* @param game
|
||||
* @param solveBanding check whether also add creatures banded with
|
||||
* attackerId
|
||||
* attackerId
|
||||
*/
|
||||
public void addBlockingGroup(UUID blockerId, UUID attackerId, UUID playerId, Game game, boolean solveBanding) {
|
||||
Permanent blocker = game.getPermanent(blockerId);
|
||||
|
|
|
|||
|
|
@ -2372,7 +2372,9 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
setStoredBookmark(game.bookmarkState()); // makes it possible to UNDO a declared attacker with costs from e.g. Propaganda
|
||||
}
|
||||
Permanent attacker = game.getPermanent(attackerId);
|
||||
if (attacker != null && attacker.canAttack(defenderId, game) && attacker.isControlledBy(playerId)) {
|
||||
if (attacker != null
|
||||
&& attacker.canAttack(defenderId, game)
|
||||
&& attacker.isControlledBy(playerId)) {
|
||||
if (!game.getCombat().declareAttacker(attackerId, defenderId, playerId, game)) {
|
||||
game.undo(playerId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,8 @@ public class TargetDefender extends TargetImpl {
|
|||
}
|
||||
}
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_PLANESWALKER, sourceControllerId, game)) {
|
||||
if ((notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game))
|
||||
if ((notTarget
|
||||
|| permanent.canBeTargetedBy(targetSource, sourceControllerId, game))
|
||||
&& filter.match(permanent, game)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
|
|
@ -84,7 +85,8 @@ public class TargetDefender extends TargetImpl {
|
|||
int count = 0;
|
||||
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null && filter.match(player, game)) {
|
||||
if (player != null
|
||||
&& filter.match(player, game)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
|
|
@ -109,13 +111,15 @@ public class TargetDefender extends TargetImpl {
|
|||
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null
|
||||
&& (notTarget || player.canBeTargetedBy(targetSource, sourceControllerId, game))
|
||||
&& (notTarget
|
||||
|| player.canBeTargetedBy(targetSource, sourceControllerId, game))
|
||||
&& filter.match(player, game)) {
|
||||
possibleTargets.add(playerId);
|
||||
}
|
||||
}
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_PLANESWALKER, sourceControllerId, game)) {
|
||||
if ((notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game))
|
||||
if ((notTarget
|
||||
|| permanent.canBeTargetedBy(targetSource, sourceControllerId, game))
|
||||
&& filter.match(permanent, game)) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
}
|
||||
|
|
@ -128,7 +132,8 @@ public class TargetDefender extends TargetImpl {
|
|||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null && filter.match(player, game)) {
|
||||
if (player != null
|
||||
&& filter.match(player, game)) {
|
||||
possibleTargets.add(playerId);
|
||||
}
|
||||
}
|
||||
|
|
@ -162,7 +167,8 @@ public class TargetDefender extends TargetImpl {
|
|||
return filter.match(player, game);
|
||||
}
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
return permanent != null && filter.match(permanent, game);
|
||||
return permanent != null
|
||||
&& filter.match(permanent, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -170,7 +176,8 @@ public class TargetDefender extends TargetImpl {
|
|||
Player player = game.getPlayer(id);
|
||||
MageObject targetSource = game.getObject(attackerId);
|
||||
if (player != null) {
|
||||
return (notTarget || player.canBeTargetedBy(targetSource, (source == null ? null : source.getControllerId()), game))
|
||||
return (notTarget
|
||||
|| player.canBeTargetedBy(targetSource, (source == null ? null : source.getControllerId()), game))
|
||||
&& filter.match(player, game);
|
||||
}
|
||||
Permanent permanent = game.getPermanent(id); // planeswalker
|
||||
|
|
@ -180,7 +187,8 @@ public class TargetDefender extends TargetImpl {
|
|||
if (source != null) {
|
||||
controllerId = source.getControllerId();
|
||||
}
|
||||
return (notTarget || permanent.canBeTargetedBy(targetSource, controllerId, game))
|
||||
return (notTarget
|
||||
|| permanent.canBeTargetedBy(targetSource, controllerId, game))
|
||||
&& filter.match(permanent, game);
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue