mirror of
https://github.com/magefree/mage.git
synced 2025-12-21 19:11:59 -08:00
Replaced some replacement effects with restriction effects. Added new method to restriction effect. Improved canAttack methods (not finished yet).
This commit is contained in:
parent
d3dadc41aa
commit
cbb6117b8e
17 changed files with 101 additions and 110 deletions
|
|
@ -944,10 +944,11 @@ public class ComputerPlayer6 extends ComputerPlayer implements Player {
|
||||||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_ATTACKERS, activePlayerId, activePlayerId))) {
|
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_ATTACKERS, activePlayerId, activePlayerId))) {
|
||||||
|
|
||||||
Player attackingPlayer = game.getPlayer(activePlayerId);
|
Player attackingPlayer = game.getPlayer(activePlayerId);
|
||||||
|
// TODO: this works only in two player game, also no attack of Planeswalker
|
||||||
UUID defenderId = game.getOpponents(playerId).iterator().next();
|
UUID defenderId = game.getOpponents(playerId).iterator().next();
|
||||||
Player defender = game.getPlayer(defenderId);
|
Player defender = game.getPlayer(defenderId);
|
||||||
|
|
||||||
List<Permanent> attackersList = super.getAvailableAttackers(game);
|
List<Permanent> attackersList = super.getAvailableAttackers(defenderId, game);
|
||||||
if (attackersList.isEmpty()) {
|
if (attackersList.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -382,9 +382,9 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
|
||||||
Integer val = null;
|
Integer val = null;
|
||||||
SimulationNode2 bestNode = null;
|
SimulationNode2 bestNode = null;
|
||||||
SimulatedPlayer2 attacker = (SimulatedPlayer2) game.getPlayer(attackerId);
|
SimulatedPlayer2 attacker = (SimulatedPlayer2) game.getPlayer(attackerId);
|
||||||
|
UUID defenderId = game.getOpponents(attackerId).iterator().next();
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(attacker.getName() + "'s possible attackers: " + attacker.getAvailableAttackers(game));
|
logger.debug(attacker.getName() + "'s possible attackers: " + attacker.getAvailableAttackers(defenderId, game));
|
||||||
}
|
}
|
||||||
for (Combat engagement: attacker.addAttackers(game)) {
|
for (Combat engagement: attacker.addAttackers(game)) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
|
|
@ -395,7 +395,6 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Game sim = game.copy();
|
Game sim = game.copy();
|
||||||
UUID defenderId = game.getOpponents(attackerId).iterator().next();
|
|
||||||
for (CombatGroup group: engagement.getGroups()) {
|
for (CombatGroup group: engagement.getGroups()) {
|
||||||
for (UUID attackId: group.getAttackers()) {
|
for (UUID attackId: group.getAttackers()) {
|
||||||
sim.getPlayer(attackerId).declareAttacker(attackId, defenderId, sim, false);
|
sim.getPlayer(attackerId).declareAttacker(attackId, defenderId, sim, false);
|
||||||
|
|
|
||||||
|
|
@ -334,7 +334,7 @@ public class SimulatedPlayer2 extends ComputerPlayer {
|
||||||
Map<Integer, Combat> engagements = new HashMap<>();
|
Map<Integer, Combat> engagements = new HashMap<>();
|
||||||
//useful only for two player games - will only attack first opponent
|
//useful only for two player games - will only attack first opponent
|
||||||
UUID defenderId = game.getOpponents(playerId).iterator().next();
|
UUID defenderId = game.getOpponents(playerId).iterator().next();
|
||||||
List<Permanent> attackersList = super.getAvailableAttackers(game);
|
List<Permanent> attackersList = super.getAvailableAttackers(defenderId, game);
|
||||||
//use binary digits to calculate powerset of attackers
|
//use binary digits to calculate powerset of attackers
|
||||||
int powerElements = (int) Math.pow(2, attackersList.size());
|
int powerElements = (int) Math.pow(2, attackersList.size());
|
||||||
StringBuilder binary = new StringBuilder();
|
StringBuilder binary = new StringBuilder();
|
||||||
|
|
|
||||||
|
|
@ -135,9 +135,10 @@ public class MCTSPlayer extends ComputerPlayer {
|
||||||
}
|
}
|
||||||
List<UUID> engagement = new ArrayList<UUID>();
|
List<UUID> engagement = new ArrayList<UUID>();
|
||||||
for (int j = 0; j < attackersList.size(); j++) {
|
for (int j = 0; j < attackersList.size(); j++) {
|
||||||
if (binary.charAt(j) == '1')
|
if (binary.charAt(j) == '1') {
|
||||||
engagement.add(attackersList.get(j).getId());
|
engagement.add(attackersList.get(j).getId());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
engagements.add(engagement);
|
engagements.add(engagement);
|
||||||
}
|
}
|
||||||
return engagements;
|
return engagements;
|
||||||
|
|
@ -146,7 +147,9 @@ public class MCTSPlayer extends ComputerPlayer {
|
||||||
public List<List<List<UUID>>> getBlocks(Game game) {
|
public List<List<List<UUID>>> getBlocks(Game game) {
|
||||||
List<List<List<UUID>>> engagements = new ArrayList<List<List<UUID>>>();
|
List<List<List<UUID>>> engagements = new ArrayList<List<List<UUID>>>();
|
||||||
int numGroups = game.getCombat().getGroups().size();
|
int numGroups = game.getCombat().getGroups().size();
|
||||||
if (numGroups == 0) return engagements;
|
if (numGroups == 0) {
|
||||||
|
return engagements;
|
||||||
|
}
|
||||||
|
|
||||||
//add a node with no blockers
|
//add a node with no blockers
|
||||||
List<List<UUID>> engagement = new ArrayList<List<UUID>>();
|
List<List<UUID>> engagement = new ArrayList<List<UUID>>();
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer {
|
||||||
//useful only for two player games - will only attack first opponent
|
//useful only for two player games - will only attack first opponent
|
||||||
// logger.info("select attackers");
|
// logger.info("select attackers");
|
||||||
UUID defenderId = game.getOpponents(playerId).iterator().next();
|
UUID defenderId = game.getOpponents(playerId).iterator().next();
|
||||||
List<Permanent> attackersList = super.getAvailableAttackers(game);
|
List<Permanent> attackersList = super.getAvailableAttackers(defenderId, game);
|
||||||
//use binary digits to calculate powerset of attackers
|
//use binary digits to calculate powerset of attackers
|
||||||
int powerElements = (int) Math.pow(2, attackersList.size());
|
int powerElements = (int) Math.pow(2, attackersList.size());
|
||||||
int value = rnd.nextInt(powerElements);
|
int value = rnd.nextInt(powerElements);
|
||||||
|
|
@ -186,9 +186,10 @@ public class SimulatedPlayerMCTS extends MCTSPlayer {
|
||||||
binary.insert(0, "0"); //pad with zeros
|
binary.insert(0, "0"); //pad with zeros
|
||||||
}
|
}
|
||||||
for (int i = 0; i < attackersList.size(); i++) {
|
for (int i = 0; i < attackersList.size(); i++) {
|
||||||
if (binary.charAt(i) == '1')
|
if (binary.charAt(i) == '1') {
|
||||||
game.getCombat().declareAttacker(attackersList.get(i).getId(), defenderId, game);
|
game.getCombat().declareAttacker(attackersList.get(i).getId(), defenderId, game);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
actionCount++;
|
actionCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -307,8 +307,10 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
|
||||||
SimulationNode bestNode = null;
|
SimulationNode bestNode = null;
|
||||||
SimulatedPlayer attacker = (SimulatedPlayer) game.getPlayer(attackerId);
|
SimulatedPlayer attacker = (SimulatedPlayer) game.getPlayer(attackerId);
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
UUID defenderId = game.getOpponents(attackerId).iterator().next();
|
||||||
logger.debug(indent(node.depth) + attacker.getName() + "'s possible attackers: " + attacker.getAvailableAttackers(game));
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(indent(node.depth) + attacker.getName() + "'s possible attackers: " + attacker.getAvailableAttackers(defenderId, game));
|
||||||
|
}
|
||||||
List<Combat> engagements = attacker.addAttackers(game);
|
List<Combat> engagements = attacker.addAttackers(game);
|
||||||
for (Combat engagement: engagements) {
|
for (Combat engagement: engagements) {
|
||||||
if (alpha >= beta) {
|
if (alpha >= beta) {
|
||||||
|
|
@ -316,7 +318,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Game sim = game.copy();
|
Game sim = game.copy();
|
||||||
UUID defenderId = game.getOpponents(attackerId).iterator().next();
|
|
||||||
for (CombatGroup group: engagement.getGroups()) {
|
for (CombatGroup group: engagement.getGroups()) {
|
||||||
for (UUID attackId: group.getAttackers()) {
|
for (UUID attackId: group.getAttackers()) {
|
||||||
sim.getPlayer(attackerId).declareAttacker(attackId, defenderId, sim, false);
|
sim.getPlayer(attackerId).declareAttacker(attackId, defenderId, sim, false);
|
||||||
|
|
@ -324,8 +326,9 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
|
||||||
}
|
}
|
||||||
sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, attackerId, attackerId));
|
sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, attackerId, attackerId));
|
||||||
SimulationNode newNode = new SimulationNode(node, sim, attackerId);
|
SimulationNode newNode = new SimulationNode(node, sim, attackerId);
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(indent(node.depth) + "simulating attack for player:" + game.getPlayer(attackerId).getName());
|
logger.debug(indent(node.depth) + "simulating attack for player:" + game.getPlayer(attackerId).getName());
|
||||||
|
}
|
||||||
sim.checkStateAndTriggered();
|
sim.checkStateAndTriggered();
|
||||||
while (!sim.getStack().isEmpty()) {
|
while (!sim.getStack().isEmpty()) {
|
||||||
sim.getStack().resolve(sim);
|
sim.getStack().resolve(sim);
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ public class SimulatedPlayer extends ComputerPlayer {
|
||||||
Map<Integer, Combat> engagements = new HashMap<Integer, Combat>();
|
Map<Integer, Combat> engagements = new HashMap<Integer, Combat>();
|
||||||
//useful only for two player games - will only attack first opponent
|
//useful only for two player games - will only attack first opponent
|
||||||
UUID defenderId = game.getOpponents(playerId).iterator().next();
|
UUID defenderId = game.getOpponents(playerId).iterator().next();
|
||||||
List<Permanent> attackersList = super.getAvailableAttackers(game);
|
List<Permanent> attackersList = super.getAvailableAttackers(defenderId, game);
|
||||||
//use binary digits to calculate powerset of attackers
|
//use binary digits to calculate powerset of attackers
|
||||||
int powerElements = (int) Math.pow(2, attackersList.size());
|
int powerElements = (int) Math.pow(2, attackersList.size());
|
||||||
StringBuilder binary = new StringBuilder();
|
StringBuilder binary = new StringBuilder();
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ public class RandomPlayer extends ComputerPlayer {
|
||||||
public void selectAttackers(Game game, UUID attackingPlayerId) {
|
public void selectAttackers(Game game, UUID attackingPlayerId) {
|
||||||
//useful only for two player games - will only attack first opponent
|
//useful only for two player games - will only attack first opponent
|
||||||
UUID defenderId = game.getOpponents(playerId).iterator().next();
|
UUID defenderId = game.getOpponents(playerId).iterator().next();
|
||||||
List<Permanent> attackersList = super.getAvailableAttackers(game);
|
List<Permanent> attackersList = super.getAvailableAttackers(defenderId, game);
|
||||||
//use binary digits to calculate powerset of attackers
|
//use binary digits to calculate powerset of attackers
|
||||||
int powerElements = (int) Math.pow(2, attackersList.size());
|
int powerElements = (int) Math.pow(2, attackersList.size());
|
||||||
int value = rnd.nextInt(powerElements);
|
int value = rnd.nextInt(powerElements);
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ public class TestPlayer extends ComputerPlayer {
|
||||||
FilterCreatureForCombat filter = new FilterCreatureForCombat();
|
FilterCreatureForCombat filter = new FilterCreatureForCombat();
|
||||||
filter.add(new NamePredicate(groups[0]));
|
filter.add(new NamePredicate(groups[0]));
|
||||||
Permanent attacker = findPermanent(filter, playerId, game);
|
Permanent attacker = findPermanent(filter, playerId, game);
|
||||||
if (attacker != null && attacker.canAttack(game)) {
|
if (attacker != null && attacker.canAttack(defenderId, game)) {
|
||||||
this.declareAttacker(attacker.getId(), defenderId, game, false);
|
this.declareAttacker(attacker.getId(), defenderId, game, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
package mage.abilities.effects;
|
package mage.abilities.effects;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.EffectType;
|
import mage.constants.EffectType;
|
||||||
|
|
@ -65,6 +66,10 @@ public abstract class RestrictionEffect extends ContinuousEffectImpl {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canAttack(UUID defenderId, Ability source, Game game) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
|
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,25 +29,22 @@
|
||||||
package mage.abilities.effects.common.combat;
|
package mage.abilities.effects.common.combat;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.MageSingleton;
|
import mage.abilities.effects.RestrictionEffect;
|
||||||
import mage.abilities.effects.ReplacementEffectImpl;
|
|
||||||
import mage.abilities.keyword.FlyingAbility;
|
import mage.abilities.keyword.FlyingAbility;
|
||||||
import mage.constants.AttachmentType;
|
import mage.constants.AttachmentType;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.Outcome;
|
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
|
||||||
import mage.game.events.GameEvent.EventType;
|
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public class CanBlockOnlyFlyingAttachedEffect extends ReplacementEffectImpl implements MageSingleton {
|
|
||||||
|
public class CanBlockOnlyFlyingAttachedEffect extends RestrictionEffect {
|
||||||
|
|
||||||
public CanBlockOnlyFlyingAttachedEffect(AttachmentType attachmentType) {
|
public CanBlockOnlyFlyingAttachedEffect(AttachmentType attachmentType) {
|
||||||
super(Duration.WhileOnBattlefield, Outcome.Detriment);
|
super(Duration.WhileOnBattlefield);
|
||||||
if (attachmentType.equals(AttachmentType.AURA)) {
|
if (attachmentType.equals(AttachmentType.AURA)) {
|
||||||
this.staticText = "Enchanted creature can block only creatures with flying";
|
this.staticText = "Enchanted creature can block only creatures with flying";
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -59,34 +56,19 @@ public class CanBlockOnlyFlyingAttachedEffect extends ReplacementEffectImpl impl
|
||||||
super(effect);
|
super(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||||
|
return permanent.getAttachments().contains(source.getSourceId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
|
||||||
|
return attacker.getAbilities().contains(FlyingAbility.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CanBlockOnlyFlyingAttachedEffect copy() {
|
public CanBlockOnlyFlyingAttachedEffect copy() {
|
||||||
return new CanBlockOnlyFlyingAttachedEffect(this);
|
return new CanBlockOnlyFlyingAttachedEffect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@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_BLOCKER) {
|
|
||||||
Permanent attachment = game.getPermanent(source.getSourceId());
|
|
||||||
if (attachment != null && attachment.getAttachedTo() != null
|
|
||||||
&& event.getSourceId().equals(attachment.getAttachedTo())) {
|
|
||||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
|
||||||
if (permanent != null && !permanent.getAbilities().containsKey(FlyingAbility.getInstance().getId())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,33 +28,24 @@
|
||||||
|
|
||||||
package mage.abilities.effects.common.combat;
|
package mage.abilities.effects.common.combat;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.MageSingleton;
|
import mage.abilities.effects.RestrictionEffect;
|
||||||
import mage.abilities.effects.ReplacementEffectImpl;
|
|
||||||
import mage.constants.AttachmentType;
|
import mage.constants.AttachmentType;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.Outcome;
|
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
|
||||||
import mage.game.events.GameEvent.EventType;
|
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public class CantAttackControllerAttachedEffect extends ReplacementEffectImpl implements MageSingleton {
|
|
||||||
|
|
||||||
/**
|
public class CantAttackControllerAttachedEffect extends RestrictionEffect {
|
||||||
* The creature this permanent is attached to can't attack the controller
|
|
||||||
* of the attachment nor it's plainswalkers
|
|
||||||
*
|
|
||||||
* @param attachmentType
|
|
||||||
*/
|
|
||||||
public CantAttackControllerAttachedEffect(AttachmentType attachmentType) {
|
public CantAttackControllerAttachedEffect(AttachmentType attachmentType) {
|
||||||
super(Duration.WhileOnBattlefield, Outcome.Detriment);
|
super(Duration.WhileOnBattlefield);
|
||||||
if (attachmentType.equals(AttachmentType.AURA)) {
|
if (attachmentType.equals(AttachmentType.AURA)) {
|
||||||
this.staticText = "Enchanted creature can't attack you or a planeswalker you control";
|
this.staticText = "Enchanted creature can't attack you or a planeswalker you control";
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -66,44 +57,24 @@ public class CantAttackControllerAttachedEffect extends ReplacementEffectImpl im
|
||||||
super(effect);
|
super(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||||
|
return permanent.getAttachments().contains(source.getSourceId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canAttack(UUID defenderId, Ability source, Game game) {
|
||||||
|
if (defenderId.equals(source.getControllerId())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Permanent plainswalker = game.getPermanent(defenderId);
|
||||||
|
return plainswalker == null || !plainswalker.getControllerId().equals(source.getSourceId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CantAttackControllerAttachedEffect copy() {
|
public CantAttackControllerAttachedEffect copy() {
|
||||||
return new CantAttackControllerAttachedEffect(this);
|
return new CantAttackControllerAttachedEffect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
|
||||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
|
||||||
Player attackingPlayer = game.getPlayer(event.getPlayerId());
|
|
||||||
if (attackingPlayer != null && sourcePermanent != null) {
|
|
||||||
game.informPlayer(attackingPlayer,
|
|
||||||
new StringBuilder("You can't attack this player or his or her planeswalker, because the attacking creature is enchanted by ")
|
|
||||||
.append(sourcePermanent.getName()).append(".").toString());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
|
||||||
if (event.getType() == EventType.DECLARE_ATTACKER) {
|
|
||||||
Permanent attachment = game.getPermanent(source.getSourceId());
|
|
||||||
if (attachment != null && attachment.getAttachedTo() != null
|
|
||||||
&& event.getSourceId().equals(attachment.getAttachedTo())) {
|
|
||||||
if (event.getTargetId().equals(source.getControllerId())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Permanent plainswalker = game.getPermanent(event.getTargetId());
|
|
||||||
if (plainswalker != null && plainswalker.getControllerId().equals(source.getSourceId())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,7 @@ public class CantAttackTargetEffect extends RestrictionEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||||
if (permanent.getId().equals(targetPointer.getFirst(game, source))) {
|
return permanent.getId().equals(targetPointer.getFirst(game, source));
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,14 @@ public interface Permanent extends Card, Controllable {
|
||||||
void setMaxBlockedBy(int maxBlockedBy);
|
void setMaxBlockedBy(int maxBlockedBy);
|
||||||
|
|
||||||
boolean canAttack(Game game);
|
boolean canAttack(Game game);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param defenderId id of planeswalker or player to attack
|
||||||
|
* @param game
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean canAttack(UUID defenderId, Game game);
|
||||||
boolean canBlock(UUID attackerId, Game game);
|
boolean canBlock(UUID attackerId, Game game);
|
||||||
boolean canBlockAny(Game game);
|
boolean canBlockAny(Game game);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -857,8 +857,15 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
return game.replaceEvent(GameEvent.getEvent(eventType, this.objectId, ownerId));
|
return game.replaceEvent(GameEvent.getEvent(eventType, this.objectId, ownerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canAttack(Game game) {
|
public boolean canAttack(Game game) {
|
||||||
|
return canAttack(null, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canAttack(UUID defenderId, Game game) {
|
||||||
if (tapped) {
|
if (tapped) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -866,10 +873,17 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
//20101001 - 508.1c
|
//20101001 - 508.1c
|
||||||
for (RestrictionEffect effect: game.getContinuousEffects().getApplicableRestrictionEffects(this, game).keySet()) {
|
for (Map.Entry<RestrictionEffect, HashSet<Ability>> effectEntry: game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) {
|
||||||
if (!effect.canAttack(game)) {
|
if (!effectEntry.getKey().canAttack(game)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (defenderId != null) {
|
||||||
|
for (Ability ability :effectEntry.getValue()) {
|
||||||
|
if (!effectEntry.getKey().canAttack(defenderId, ability, game)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return !abilities.containsKey(DefenderAbility.getInstance().getId())
|
return !abilities.containsKey(DefenderAbility.getInstance().getId())
|
||||||
|| game.getContinuousEffects().asThough(this.objectId, AsThoughEffectType.ATTACK, this.getControllerId(), game);
|
|| game.getContinuousEffects().asThough(this.objectId, AsThoughEffectType.ATTACK, this.getControllerId(), game);
|
||||||
|
|
|
||||||
|
|
@ -321,6 +321,7 @@ public interface Player extends MageItem, Copyable<Player> {
|
||||||
void declareAttacker(UUID attackerId, UUID defenderId, Game game, boolean allowUndo);
|
void declareAttacker(UUID attackerId, UUID defenderId, Game game, boolean allowUndo);
|
||||||
void declareBlocker(UUID defenderId, UUID blockerId, UUID attackerId, Game game);
|
void declareBlocker(UUID defenderId, UUID blockerId, UUID attackerId, Game game);
|
||||||
List<Permanent> getAvailableAttackers(Game game);
|
List<Permanent> getAvailableAttackers(Game game);
|
||||||
|
List<Permanent> getAvailableAttackers(UUID defenderId, Game game);
|
||||||
List<Permanent> getAvailableBlockers(Game game);
|
List<Permanent> getAvailableBlockers(Game game);
|
||||||
|
|
||||||
void beginTurn(Game game);
|
void beginTurn(Game game);
|
||||||
|
|
|
||||||
|
|
@ -1673,7 +1673,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
setStoredBookmark(game.bookmarkState()); // makes it possible to UNDO a declared attacker with costs from e.g. Propaganda
|
setStoredBookmark(game.bookmarkState()); // makes it possible to UNDO a declared attacker with costs from e.g. Propaganda
|
||||||
}
|
}
|
||||||
Permanent attacker = game.getPermanent(attackerId);
|
Permanent attacker = game.getPermanent(attackerId);
|
||||||
if (attacker != null && attacker.canAttack(game) && attacker.getControllerId().equals(playerId)) {
|
if (attacker != null && attacker.canAttack(defenderId, game) && attacker.getControllerId().equals(playerId)) {
|
||||||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_ATTACKER, defenderId, attackerId, playerId))) {
|
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_ATTACKER, defenderId, attackerId, playerId))) {
|
||||||
game.getCombat().declareAttacker(attackerId, defenderId, game);
|
game.getCombat().declareAttacker(attackerId, defenderId, game);
|
||||||
}
|
}
|
||||||
|
|
@ -1767,11 +1767,17 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Permanent> getAvailableAttackers(Game game) {
|
public List<Permanent> getAvailableAttackers(Game game) {
|
||||||
|
// TODO: get available opponents and their planeswalkers, check for each if permanent can attack one
|
||||||
|
return getAvailableAttackers(null, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Permanent> getAvailableAttackers(UUID defenderId, Game game) {
|
||||||
FilterCreatureForCombat filter = new FilterCreatureForCombat();
|
FilterCreatureForCombat filter = new FilterCreatureForCombat();
|
||||||
List<Permanent> attackers = game.getBattlefield().getAllActivePermanents(filter, playerId, game);
|
List<Permanent> attackers = game.getBattlefield().getAllActivePermanents(filter, playerId, game);
|
||||||
for (Iterator<Permanent> i = attackers.iterator(); i.hasNext();) {
|
for (Iterator<Permanent> i = attackers.iterator(); i.hasNext();) {
|
||||||
Permanent entry = i.next();
|
Permanent entry = i.next();
|
||||||
if (!entry.canAttack(game)) {
|
if (!entry.canAttack(defenderId, game)) {
|
||||||
i.remove();
|
i.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue