mirror of
https://github.com/correl/mage.git
synced 2024-12-24 03:00:14 +00:00
* Fixed a bug that the AI did for target selection not check correctly players with hexproof ability.
This commit is contained in:
parent
503dad24b3
commit
8686f4f777
10 changed files with 48 additions and 29 deletions
|
@ -432,24 +432,24 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
UUID opponentId = game.getOpponents(playerId).iterator().next();
|
||||
if (target instanceof TargetPlayer) {
|
||||
if (outcome.isGood()) {
|
||||
if (target.canTarget(playerId, source, game)) {
|
||||
if (target.canTarget(playerId, playerId, source, game)) {
|
||||
target.addTarget(playerId, source, game);
|
||||
return true;
|
||||
}
|
||||
if (target.isRequired(source)) {
|
||||
if (target.canTarget(opponentId, source, game)) {
|
||||
if (target.canTarget(playerId, opponentId, source, game)) {
|
||||
target.addTarget(opponentId, source, game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (target.canTarget(opponentId, source, game)) {
|
||||
if (target.canTarget(playerId, opponentId, source, game)) {
|
||||
target.addTarget(opponentId, source, game);
|
||||
return true;
|
||||
}
|
||||
if (target.isRequired(source)) {
|
||||
if (target.canTarget(playerId, source, game)) {
|
||||
if (target.canTarget(playerId, playerId, source, game)) {
|
||||
target.addTarget(playerId, source, game);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -51,7 +51,6 @@ public class SublimeArchangel extends CardImpl {
|
|||
this.expansionSetCode = "M13";
|
||||
this.subtype.add("Angel");
|
||||
|
||||
this.color.setWhite(true);
|
||||
this.power = new MageInt(4);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
|
|
|
@ -74,4 +74,30 @@ public class DontUntapTest extends CardTestPlayerBase {
|
|||
assertLife(playerB, 20);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* I used Ajani Vengeant's +1 on a Sublime Archangel and it untap on it's controller's upkeep.
|
||||
*/
|
||||
@Test
|
||||
public void TestAjaniVengeantFirst() {
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Sublime Archangel", 1); // 4/3
|
||||
|
||||
// +1: Target permanent doesn't untap during its controller's next untap step.
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Ajani Vengeant", 1);
|
||||
|
||||
attack(1, playerA, "Sublime Archangel");
|
||||
|
||||
activateAbility(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "+1: Target permanent doesn't","Sublime Archangel");
|
||||
|
||||
setStopAt(3, PhaseStep.DRAW);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20);
|
||||
assertLife(playerB, 15); // 4 + 1 from Exalted
|
||||
|
||||
assertTapped("Sublime Archangel", true);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -261,7 +261,7 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
boolean playLand(Card card, Game game);
|
||||
boolean activateAbility(ActivatedAbility ability, Game game);
|
||||
boolean triggerAbility(TriggeredAbility ability, Game game);
|
||||
boolean canBeTargetedBy(MageObject source, Game game);
|
||||
boolean canBeTargetedBy(MageObject source, UUID sourceControllerId, Game game);
|
||||
boolean hasProtectionFrom(MageObject source, Game game);
|
||||
boolean flipCoin(Game game);
|
||||
boolean flipCoin(Game game, ArrayList<UUID> appliedEffects);
|
||||
|
|
|
@ -583,7 +583,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeTargetedBy(MageObject source, Game game) {
|
||||
public boolean canBeTargetedBy(MageObject source, UUID sourceControllerId, Game game) {
|
||||
if (this.hasLost() || this.hasLeft()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -592,13 +592,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return false;
|
||||
}
|
||||
if (abilities.containsKey(HexproofAbility.getInstance().getId())) {
|
||||
UUID controllerId = null;
|
||||
if (source instanceof Permanent) {
|
||||
controllerId = ((Permanent) source).getControllerId();
|
||||
} else if (source instanceof StackObject) {
|
||||
controllerId = ((StackObject) source).getControllerId();
|
||||
}
|
||||
if (controllerId != null && this.hasOpponent(controllerId, game)
|
||||
if (sourceControllerId != null && this.hasOpponent(sourceControllerId, game)
|
||||
&& !game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, this.getId(), game)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ public class TargetPlayer extends TargetImpl {
|
|||
for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null && !player.hasLeft() && filter.match(player, sourceId, sourceControllerId, game)) {
|
||||
if (player.canBeTargetedBy(targetSource, game)) {
|
||||
if (player.canBeTargetedBy(targetSource, sourceControllerId, game)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
|
@ -133,7 +133,7 @@ public class TargetPlayer extends TargetImpl {
|
|||
for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null && !player.hasLeft() && filter.match(player, sourceId, sourceControllerId, game)) {
|
||||
if (isNotTarget() || player.canBeTargetedBy(targetSource, game)) {
|
||||
if (isNotTarget() || player.canBeTargetedBy(targetSource, sourceControllerId, game)) {
|
||||
possibleTargets.add(playerId);
|
||||
}
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ public class TargetPlayer extends TargetImpl {
|
|||
Player player = game.getPlayer(id);
|
||||
if (player != null) {
|
||||
if (source != null) {
|
||||
return (isNotTarget() || player.canBeTargetedBy(game.getObject(source.getSourceId()), game))
|
||||
return (isNotTarget() || player.canBeTargetedBy(game.getObject(source.getSourceId()), source.getControllerId(), game))
|
||||
&& filter.match(player, source.getSourceId(), source.getControllerId(), game);
|
||||
} else {
|
||||
return filter.match(player, game);
|
||||
|
|
|
@ -106,7 +106,7 @@ public class TargetCreatureOrPlayer extends TargetImpl {
|
|||
return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(permanent, source.getSourceId(), source.getControllerId(), game);
|
||||
}
|
||||
if (player != null) {
|
||||
return player.canBeTargetedBy(targetSource, game) && filter.match(player, game);
|
||||
return player.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(player, game);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ public class TargetCreatureOrPlayer extends TargetImpl {
|
|||
MageObject targetSource = game.getObject(sourceId);
|
||||
for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null && player.canBeTargetedBy(targetSource, game) && filter.match(player, game)) {
|
||||
if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
|
@ -189,7 +189,7 @@ public class TargetCreatureOrPlayer extends TargetImpl {
|
|||
MageObject targetSource = game.getObject(sourceId);
|
||||
for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null && player.canBeTargetedBy(targetSource, game) && filter.match(player, game)) {
|
||||
if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) {
|
||||
possibleTargets.add(playerId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ public class TargetCreatureOrPlayerAmount extends TargetAmount {
|
|||
return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(permanent, source.getSourceId(), source.getControllerId(), game);
|
||||
}
|
||||
if (player != null) {
|
||||
return player.canBeTargetedBy(targetSource, game) && filter.match(player, game);
|
||||
return player.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(player, game);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ public class TargetCreatureOrPlayerAmount extends TargetAmount {
|
|||
MageObject targetSource = game.getObject(sourceId);
|
||||
for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null && player.canBeTargetedBy(targetSource, game) && filter.match(player, game)) {
|
||||
if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
|
@ -173,7 +173,7 @@ public class TargetCreatureOrPlayerAmount extends TargetAmount {
|
|||
MageObject targetSource = game.getObject(sourceId);
|
||||
for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null && player.canBeTargetedBy(targetSource, game) && filter.match(player, game)) {
|
||||
if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) {
|
||||
possibleTargets.add(playerId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ public class TargetDefender extends TargetImpl {
|
|||
for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
// removed canBeTargeted because it's not correct to check it for attacking target
|
||||
if (player != null && player.canBeTargetedBy(targetSource, game) && filter.match(player, game)) {
|
||||
if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
|
@ -135,7 +135,7 @@ public class TargetDefender extends TargetImpl {
|
|||
MageObject targetSource = game.getObject(sourceId);
|
||||
for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null && player.canBeTargetedBy(targetSource, game) && filter.match(player, game)) {
|
||||
if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) {
|
||||
possibleTargets.add(playerId);
|
||||
}
|
||||
}
|
||||
|
@ -198,7 +198,7 @@ public class TargetDefender extends TargetImpl {
|
|||
Player player = game.getPlayer(id);
|
||||
MageObject targetSource = game.getObject(attackerId);
|
||||
if (player != null) {
|
||||
return notTarget || (player.canBeTargetedBy(targetSource, game) && filter.match(player, game));
|
||||
return notTarget || (player.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(player, game));
|
||||
}
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
if (permanent != null) {
|
||||
|
|
|
@ -126,7 +126,7 @@ public class TargetPermanentOrPlayer extends TargetImpl {
|
|||
}
|
||||
if (player != null) {
|
||||
if (!isNotTarget()) {
|
||||
if (!player.canBeTargetedBy(targetSource, game)) {
|
||||
if (!player.canBeTargetedBy(targetSource, source.getControllerId(), game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ public class TargetPermanentOrPlayer extends TargetImpl {
|
|||
MageObject targetSource = game.getObject(sourceId);
|
||||
for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null && player.canBeTargetedBy(targetSource, game) && filter.match(player, game)) {
|
||||
if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
|
@ -213,7 +213,7 @@ public class TargetPermanentOrPlayer extends TargetImpl {
|
|||
MageObject targetSource = game.getObject(sourceId);
|
||||
for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null && (notTarget || player.canBeTargetedBy(targetSource, game)) && filter.match(player, game)) {
|
||||
if (player != null && (notTarget || player.canBeTargetedBy(targetSource, sourceControllerId, game)) && filter.match(player, game)) {
|
||||
possibleTargets.add(playerId);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue