mirror of
https://github.com/correl/mage.git
synced 2025-04-10 01:01:05 -09:00
Added logic to limit number of allowed attackers attacking defending player.
This commit is contained in:
parent
b6275c1bae
commit
b1250353ee
6 changed files with 207 additions and 59 deletions
Mage/src/mage
abilities
game/combat
players
target
|
@ -33,6 +33,7 @@ import mage.abilities.effects.Effect;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.target.targetpointer.FixedTarget;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -40,13 +41,20 @@ import mage.game.events.GameEvent;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class GainLifeControllerTriggeredAbility extends TriggeredAbilityImpl<GainLifeControllerTriggeredAbility> {
|
public class GainLifeControllerTriggeredAbility extends TriggeredAbilityImpl<GainLifeControllerTriggeredAbility> {
|
||||||
|
private boolean setTargetPointer;
|
||||||
|
|
||||||
public GainLifeControllerTriggeredAbility(Effect effect, boolean optional) {
|
public GainLifeControllerTriggeredAbility(Effect effect, boolean optional) {
|
||||||
|
this(effect, optional, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GainLifeControllerTriggeredAbility(Effect effect, boolean optional, boolean setTargetPointer) {
|
||||||
super(Zone.BATTLEFIELD, effect, optional);
|
super(Zone.BATTLEFIELD, effect, optional);
|
||||||
|
this.setTargetPointer = setTargetPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GainLifeControllerTriggeredAbility(final GainLifeControllerTriggeredAbility ability) {
|
public GainLifeControllerTriggeredAbility(final GainLifeControllerTriggeredAbility ability) {
|
||||||
super(ability);
|
super(ability);
|
||||||
|
this.setTargetPointer = ability.setTargetPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -56,7 +64,16 @@ public class GainLifeControllerTriggeredAbility extends TriggeredAbilityImpl<Gai
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
return event.getType() == GameEvent.EventType.GAINED_LIFE && event.getPlayerId().equals(this.getControllerId());
|
if (event.getType() == GameEvent.EventType.GAINED_LIFE && event.getPlayerId().equals(this.getControllerId())) {
|
||||||
|
if (setTargetPointer) {
|
||||||
|
for (Effect effect : this.getEffects()) {
|
||||||
|
effect.setTargetPointer(new FixedTarget(event.getPlayerId()));
|
||||||
|
effect.setValue("gainedLife", event.getAmount());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -45,22 +45,41 @@ import mage.game.permanent.Permanent;
|
||||||
*/
|
*/
|
||||||
public class GainControlTargetEffect extends ContinuousEffectImpl<GainControlTargetEffect> {
|
public class GainControlTargetEffect extends ContinuousEffectImpl<GainControlTargetEffect> {
|
||||||
|
|
||||||
private UUID fixedControllerId;
|
private UUID controllingPlayerId;
|
||||||
private boolean fixedController;
|
private boolean fixedControl;
|
||||||
|
|
||||||
public GainControlTargetEffect(Duration duration) {
|
public GainControlTargetEffect(Duration duration) {
|
||||||
this(duration, false);
|
this(duration, false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GainControlTargetEffect(Duration duration, boolean fixedController) {
|
/**
|
||||||
|
*
|
||||||
|
* @param duration
|
||||||
|
* @param fixedControl Controlling player is fixed even if the controller of the ability chnages
|
||||||
|
*/
|
||||||
|
public GainControlTargetEffect(Duration duration, boolean fixedControl) {
|
||||||
|
this(duration, fixedControl, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param duration
|
||||||
|
* @param controllingPlayerId Player that controlls the target creature
|
||||||
|
*/
|
||||||
|
public GainControlTargetEffect(Duration duration, UUID controllingPlayerId) {
|
||||||
|
this(duration, true, controllingPlayerId);
|
||||||
|
|
||||||
|
}
|
||||||
|
public GainControlTargetEffect(Duration duration, boolean fixedControl, UUID controllingPlayerId) {
|
||||||
super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl);
|
super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl);
|
||||||
this.fixedController = fixedController;
|
this.controllingPlayerId = controllingPlayerId;
|
||||||
|
this.fixedControl = fixedControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GainControlTargetEffect(final GainControlTargetEffect effect) {
|
public GainControlTargetEffect(final GainControlTargetEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
this.fixedControllerId = effect.fixedControllerId;
|
this.controllingPlayerId = effect.controllingPlayerId;
|
||||||
this.fixedController = effect.fixedController;
|
this.fixedControl = effect.fixedControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -70,8 +89,8 @@ public class GainControlTargetEffect extends ContinuousEffectImpl<GainControlTar
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Ability source, Game game) {
|
public void init(Ability source, Game game) {
|
||||||
if (fixedController) {
|
if (this.controllingPlayerId == null && fixedControl) {
|
||||||
this.fixedControllerId = source.getControllerId();
|
this.controllingPlayerId = source.getControllerId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,18 +98,21 @@ public class GainControlTargetEffect extends ContinuousEffectImpl<GainControlTar
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source));
|
Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source));
|
||||||
if (permanent != null) {
|
if (permanent != null) {
|
||||||
if (fixedController) {
|
if (controllingPlayerId != null) {
|
||||||
return permanent.changeControllerId(fixedControllerId, game);
|
return permanent.changeControllerId(controllingPlayerId, game);
|
||||||
} else {
|
} else {
|
||||||
return permanent.changeControllerId(source.getControllerId(), game);
|
return permanent.changeControllerId(source.getControllerId(), game);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
this.discard();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getText(Mode mode) {
|
public String getText(Mode mode) {
|
||||||
|
if (!staticText.isEmpty()) {
|
||||||
|
return staticText;
|
||||||
|
}
|
||||||
return "Gain control of target " + mode.getTargets().get(0).getTargetName() + " " + duration.toString();
|
return "Gain control of target " + mode.getTargets().get(0).getTargetName() + " " + duration.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.players.PlayerList;
|
import mage.players.PlayerList;
|
||||||
import mage.target.common.TargetDefender;
|
import mage.target.common.TargetDefender;
|
||||||
|
import mage.util.CardUtil;
|
||||||
import mage.util.Copyable;
|
import mage.util.Copyable;
|
||||||
import mage.util.trace.TraceUtil;
|
import mage.util.trace.TraceUtil;
|
||||||
|
|
||||||
|
@ -70,10 +71,15 @@ public class Combat implements Serializable, Copyable<Combat> {
|
||||||
protected List<CombatGroup> groups = new ArrayList<CombatGroup>();
|
protected List<CombatGroup> groups = new ArrayList<CombatGroup>();
|
||||||
protected Map<UUID, CombatGroup> blockingGroups = new HashMap<UUID, CombatGroup>();
|
protected Map<UUID, CombatGroup> blockingGroups = new HashMap<UUID, CombatGroup>();
|
||||||
protected Set<UUID> defenders = new HashSet<UUID>();
|
protected Set<UUID> defenders = new HashSet<UUID>();
|
||||||
|
// how many creatures attack defending player
|
||||||
|
protected Map<UUID, Set<UUID>> numberCreaturesDefenderAttackedBy = new HashMap<UUID, Set<UUID>>();
|
||||||
protected UUID attackerId; //the player that is attacking
|
protected UUID attackerId; //the player that is attacking
|
||||||
// <creature that can block, <all attackers that force the creature to block it>>
|
// <creature that can block, <all attackers that force the creature to block it>>
|
||||||
protected Map<UUID, Set<UUID>> creaturesForcedToBlockAttackers = new HashMap<UUID, Set<UUID>>();
|
protected Map<UUID, Set<UUID>> creaturesForcedToBlockAttackers = new HashMap<UUID, Set<UUID>>();
|
||||||
|
|
||||||
|
// which creature is forced to attack which defender(s). If set is empty, the creature can attack every possible defender
|
||||||
|
private final Map<UUID, Set<UUID>> creaturesForcedToAttack = new HashMap<UUID, Set<UUID>>();
|
||||||
|
private int maxAttackers = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
|
||||||
public Combat() {
|
public Combat() {
|
||||||
|
@ -138,6 +144,9 @@ public class Combat implements Serializable, Copyable<Combat> {
|
||||||
defenders.clear();
|
defenders.clear();
|
||||||
attackerId = null;
|
attackerId = null;
|
||||||
creaturesForcedToBlockAttackers.clear();
|
creaturesForcedToBlockAttackers.clear();
|
||||||
|
numberCreaturesDefenderAttackedBy.clear();
|
||||||
|
creaturesForcedToAttack.clear();
|
||||||
|
maxAttackers = Integer.MIN_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getValue() {
|
public String getValue() {
|
||||||
|
@ -207,27 +216,38 @@ public class Combat implements Serializable, Copyable<Combat> {
|
||||||
protected void checkAttackRequirements(Player player, Game game) {
|
protected void checkAttackRequirements(Player player, Game game) {
|
||||||
//20101001 - 508.1d
|
//20101001 - 508.1d
|
||||||
for (Permanent creature : player.getAvailableAttackers(game)) {
|
for (Permanent creature : player.getAvailableAttackers(game)) {
|
||||||
|
boolean mustAttack = false;
|
||||||
|
Set <UUID> defendersForcedToAttack = new HashSet<UUID>();
|
||||||
for (Map.Entry entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, game).entrySet()) {
|
for (Map.Entry entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, game).entrySet()) {
|
||||||
RequirementEffect effect = (RequirementEffect)entry.getKey();
|
RequirementEffect effect = (RequirementEffect)entry.getKey();
|
||||||
if (effect.mustAttack(game)) {
|
if (effect.mustAttack(game)) {
|
||||||
|
mustAttack = true;
|
||||||
for (Ability ability: (HashSet<Ability>)entry.getValue()) {
|
for (Ability ability: (HashSet<Ability>)entry.getValue()) {
|
||||||
UUID defenderId = effect.mustAttackDefender(ability, game);
|
UUID defenderId = effect.mustAttackDefender(ability, game);
|
||||||
if (defenderId == null) {
|
if(defenderId != null) {
|
||||||
if (defenders.size() == 1) {
|
defendersForcedToAttack.add(defenderId);
|
||||||
player.declareAttacker(creature.getId(), defenders.iterator().next(), game);
|
|
||||||
} else {
|
|
||||||
TargetDefender target = new TargetDefender(defenders, creature.getId());
|
|
||||||
target.setRequired(true);
|
|
||||||
if (player.chooseTarget(Outcome.Damage, target, null, game)) {
|
|
||||||
player.declareAttacker(creature.getId(), target.getFirstTarget(), game);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
player.declareAttacker(creature.getId(), defenderId, game);
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mustAttack) {
|
||||||
|
creaturesForcedToAttack.put(creature.getId(),defendersForcedToAttack);
|
||||||
|
if (defendersForcedToAttack.isEmpty()) {
|
||||||
|
if (defenders.size() == 1) {
|
||||||
|
player.declareAttacker(creature.getId(), defenders.iterator().next(), game);
|
||||||
|
} else {
|
||||||
|
TargetDefender target = new TargetDefender(defenders, creature.getId());
|
||||||
|
target.setRequired(true);
|
||||||
|
if (player.chooseTarget(Outcome.Damage, target, null, game)) {
|
||||||
|
player.declareAttacker(creature.getId(), target.getFirstTarget(), game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
player.declareAttacker(creature.getId(), defendersForcedToAttack.iterator().next(), game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,35 +320,42 @@ public class Combat implements Serializable, Copyable<Combat> {
|
||||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, defenderId, defenderId));
|
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, defenderId, defenderId));
|
||||||
|
|
||||||
// add info about attacker blocked by blocker to the game log
|
// add info about attacker blocked by blocker to the game log
|
||||||
|
boolean shownDefendingPlayer = false;
|
||||||
for (CombatGroup group :this.getGroups()) {
|
for (CombatGroup group :this.getGroups()) {
|
||||||
StringBuilder sb = new StringBuilder();
|
if (group.defendingPlayerId.equals(defenderId)) {
|
||||||
for(UUID attackingCreatureId : group.getAttackers()) {
|
if (!shownDefendingPlayer && defender != null) {
|
||||||
Permanent attackingCreature = game.getPermanent(attackingCreatureId);
|
game.informPlayers(new StringBuilder("Attacked player: ").append(defender.getName()).toString());
|
||||||
if (attackingCreature != null) {
|
shownDefendingPlayer = true;
|
||||||
sb.append(attackingCreature.getName()).append(" (");
|
}
|
||||||
sb.append(attackingCreature.getPower().getValue()).append("/").append(attackingCreature.getToughness().getValue()).append(") ");
|
StringBuilder sb = new StringBuilder();
|
||||||
} else {
|
for(UUID attackingCreatureId : group.getAttackers()) {
|
||||||
// creature left battlefield
|
Permanent attackingCreature = game.getPermanent(attackingCreatureId);
|
||||||
attackingCreature = (Permanent) game.getLastKnownInformation(attackingCreatureId, Zone.BATTLEFIELD);
|
|
||||||
if (attackingCreature != null) {
|
if (attackingCreature != null) {
|
||||||
sb.append(attackingCreature.getName()).append(" [left battlefield)] ");
|
sb.append(attackingCreature.getName()).append(" (");
|
||||||
|
sb.append(attackingCreature.getPower().getValue()).append("/").append(attackingCreature.getToughness().getValue()).append(") ");
|
||||||
|
} else {
|
||||||
|
// creature left battlefield
|
||||||
|
attackingCreature = (Permanent) game.getLastKnownInformation(attackingCreatureId, Zone.BATTLEFIELD);
|
||||||
|
if (attackingCreature != null) {
|
||||||
|
sb.append(attackingCreature.getName()).append(" [left battlefield)] ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (group.getBlockers().size() > 0) {
|
||||||
if (group.getBlockers().size() > 0) {
|
sb.append("blocked by ");
|
||||||
sb.append("blocked by ");
|
for(UUID blockingCreatureId : group.getBlockers()) {
|
||||||
for(UUID blockingCreatureId : group.getBlockers()) {
|
Permanent blockingCreature = game.getPermanent(blockingCreatureId);
|
||||||
Permanent blockingCreature = game.getPermanent(blockingCreatureId);
|
if (blockingCreature != null) {
|
||||||
if (blockingCreature != null) {
|
sb.append(blockingCreature.getName()).append(" (");
|
||||||
sb.append(blockingCreature.getName()).append(" (");
|
sb.append(blockingCreature.getPower().getValue()).append("/").append(blockingCreature.getToughness().getValue()).append(") ");
|
||||||
sb.append(blockingCreature.getPower().getValue()).append("/").append(blockingCreature.getToughness().getValue()).append(") ");
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
} else{
|
} else{
|
||||||
sb.append("unblocked");
|
sb.append("unblocked");
|
||||||
|
}
|
||||||
|
game.informPlayers(sb.toString());
|
||||||
}
|
}
|
||||||
game.informPlayers(sb.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -647,17 +674,38 @@ public class Combat implements Serializable, Copyable<Combat> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addDefender(UUID defenderId, Game game) {
|
private void addDefender(UUID defenderId, Game game) {
|
||||||
defenders.add(defenderId);
|
if (!defenders.contains(defenderId)) {
|
||||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filterPlaneswalker, defenderId, game)) {
|
if (maxAttackers < Integer.MAX_VALUE) {
|
||||||
defenders.add(permanent.getId());
|
Player defendingPlayer = game.getPlayer(defenderId);
|
||||||
|
if (defendingPlayer != null) {
|
||||||
|
if (defendingPlayer.getMaxAttackedBy() == Integer.MAX_VALUE) {
|
||||||
|
maxAttackers = Integer.MAX_VALUE;
|
||||||
|
} else {
|
||||||
|
if (maxAttackers == Integer.MIN_VALUE) {
|
||||||
|
maxAttackers = defendingPlayer.getMaxAttackedBy();
|
||||||
|
} else {
|
||||||
|
maxAttackers += defendingPlayer.getMaxAttackedBy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defenders.add(defenderId);
|
||||||
|
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filterPlaneswalker, defenderId, game)) {
|
||||||
|
defenders.add(permanent.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void declareAttacker(UUID attackerId, UUID defenderId, Game game) {
|
public boolean declareAttacker(UUID attackerId, UUID defenderId, Game game) {
|
||||||
if (!defenders.contains(defenderId)) {
|
if (!defenders.contains(defenderId)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
Permanent defender = game.getPermanent(defenderId);
|
Permanent defender = game.getPermanent(defenderId);
|
||||||
|
// Check if defending player can be attacked with another creature
|
||||||
|
if (!canDefenderBeAttacked(attackerId, defenderId, game)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
CombatGroup newGroup = new CombatGroup(defenderId, defender != null, defender != null ? defender.getControllerId(): defenderId);
|
CombatGroup newGroup = new CombatGroup(defenderId, defender != null, defender != null ? defender.getControllerId(): defenderId);
|
||||||
newGroup.attackers.add(attackerId);
|
newGroup.attackers.add(attackerId);
|
||||||
Permanent attacker = game.getPermanent(attackerId);
|
Permanent attacker = game.getPermanent(attackerId);
|
||||||
|
@ -666,6 +714,39 @@ public class Combat implements Serializable, Copyable<Combat> {
|
||||||
}
|
}
|
||||||
attacker.setAttacking(true);
|
attacker.setAttacking(true);
|
||||||
groups.add(newGroup);
|
groups.add(newGroup);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canDefenderBeAttacked(UUID attackerId, UUID defenderId, Game game) {
|
||||||
|
Permanent defender = game.getPermanent(defenderId);
|
||||||
|
// Check if defending player can be attacked with another creature
|
||||||
|
if (defender != null) {
|
||||||
|
// a planeswalker is attacked, there exits no restriction yet for attacking planeswalker
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Player defendingPlayer = game.getPlayer(defenderId);
|
||||||
|
if (defendingPlayer == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Set<UUID> defenderAttackedBy;
|
||||||
|
if (numberCreaturesDefenderAttackedBy.containsKey(defendingPlayer.getId())) {
|
||||||
|
defenderAttackedBy = numberCreaturesDefenderAttackedBy.get(defendingPlayer.getId());
|
||||||
|
} else {
|
||||||
|
defenderAttackedBy = new HashSet<UUID>();
|
||||||
|
numberCreaturesDefenderAttackedBy.put(defendingPlayer.getId(), defenderAttackedBy);
|
||||||
|
}
|
||||||
|
if (defenderAttackedBy.size() >= defendingPlayer.getMaxAttackedBy()) {
|
||||||
|
Player attackingPlayer = game.getPlayer(game.getControllerId(attackerId));
|
||||||
|
if (attackingPlayer != null) {
|
||||||
|
game.informPlayer(attackingPlayer, new StringBuilder("No more than ")
|
||||||
|
.append(CardUtil.numberToText(defendingPlayer.getMaxAttackedBy()))
|
||||||
|
.append(" creatures can attack ")
|
||||||
|
.append(defendingPlayer.getName()).toString());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
defenderAttackedBy.add(attackerId);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add blocking group for creatures that block more than one creature
|
// add blocking group for creatures that block more than one creature
|
||||||
|
@ -757,10 +838,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean noAttackers() {
|
public boolean noAttackers() {
|
||||||
if (groups.isEmpty() || getAttackers().isEmpty()) {
|
return groups.isEmpty() || getAttackers().isEmpty();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAttacked(UUID defenderId, Game game) {
|
public boolean isAttacked(UUID defenderId, Game game) {
|
||||||
|
@ -845,6 +923,9 @@ public class Combat implements Serializable, Copyable<Combat> {
|
||||||
if (group.attackers.contains(attackerId)) {
|
if (group.attackers.contains(attackerId)) {
|
||||||
group.attackers.remove(attackerId);
|
group.attackers.remove(attackerId);
|
||||||
group.attackerOrder.remove(attackerId);
|
group.attackerOrder.remove(attackerId);
|
||||||
|
for (Set<UUID> attackingCreatures : numberCreaturesDefenderAttackedBy.values()) {
|
||||||
|
attackingCreatures.remove(attackerId);
|
||||||
|
}
|
||||||
Permanent creature = game.getPermanent(attackerId);
|
Permanent creature = game.getPermanent(attackerId);
|
||||||
if (creature != null) {
|
if (creature != null) {
|
||||||
creature.setAttacking(false);
|
creature.setAttacking(false);
|
||||||
|
@ -878,6 +959,15 @@ public class Combat implements Serializable, Copyable<Combat> {
|
||||||
return attackerId;
|
return attackerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<UUID, Set<UUID>> getCreaturesForcedToAttack() {
|
||||||
|
return creaturesForcedToAttack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxAttackers() {
|
||||||
|
return maxAttackers;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Combat copy() {
|
public Combat copy() {
|
||||||
return new Combat(this);
|
return new Combat(this);
|
||||||
|
|
|
@ -102,6 +102,8 @@ public interface Player extends MageItem, Copyable<Player> {
|
||||||
void setLandsPerTurn(int landsPerTurn);
|
void setLandsPerTurn(int landsPerTurn);
|
||||||
int getMaxHandSize();
|
int getMaxHandSize();
|
||||||
void setMaxHandSize(int maxHandSize);
|
void setMaxHandSize(int maxHandSize);
|
||||||
|
int getMaxAttackedBy();
|
||||||
|
void setMaxAttackedBy(int maxAttackedBy);
|
||||||
boolean isPassed();
|
boolean isPassed();
|
||||||
boolean isEmptyDraw();
|
boolean isEmptyDraw();
|
||||||
void pass(Game game);
|
void pass(Game game);
|
||||||
|
|
|
@ -139,6 +139,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
||||||
protected int landsPlayed;
|
protected int landsPlayed;
|
||||||
protected int landsPerTurn = 1;
|
protected int landsPerTurn = 1;
|
||||||
protected int maxHandSize = 7;
|
protected int maxHandSize = 7;
|
||||||
|
protected int maxAttackedBy = Integer.MAX_VALUE;
|
||||||
protected ManaPool manaPool;
|
protected ManaPool manaPool;
|
||||||
protected boolean passed;
|
protected boolean passed;
|
||||||
protected boolean passedTurn;
|
protected boolean passedTurn;
|
||||||
|
@ -219,6 +220,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
||||||
this.landsPlayed = player.landsPlayed;
|
this.landsPlayed = player.landsPlayed;
|
||||||
this.landsPerTurn = player.landsPerTurn;
|
this.landsPerTurn = player.landsPerTurn;
|
||||||
this.maxHandSize = player.maxHandSize;
|
this.maxHandSize = player.maxHandSize;
|
||||||
|
this.maxAttackedBy = player.maxAttackedBy;
|
||||||
this.manaPool = player.manaPool.copy();
|
this.manaPool = player.manaPool.copy();
|
||||||
this.turns = player.turns;
|
this.turns = player.turns;
|
||||||
|
|
||||||
|
@ -269,6 +271,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
||||||
this.landsPlayed = player.getLandsPlayed();
|
this.landsPlayed = player.getLandsPlayed();
|
||||||
this.landsPerTurn = player.getLandsPerTurn();
|
this.landsPerTurn = player.getLandsPerTurn();
|
||||||
this.maxHandSize = player.getMaxHandSize();
|
this.maxHandSize = player.getMaxHandSize();
|
||||||
|
this.maxAttackedBy = player.getMaxAttackedBy();
|
||||||
this.manaPool = player.getManaPool().copy();
|
this.manaPool = player.getManaPool().copy();
|
||||||
this.turns = player.getTurns();
|
this.turns = player.getTurns();
|
||||||
|
|
||||||
|
@ -345,6 +348,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
||||||
this.abilities.clear();
|
this.abilities.clear();
|
||||||
this.landsPerTurn = 1;
|
this.landsPerTurn = 1;
|
||||||
this.maxHandSize = 7;
|
this.maxHandSize = 7;
|
||||||
|
this.maxAttackedBy = Integer.MAX_VALUE;
|
||||||
this.canGainLife = true;
|
this.canGainLife = true;
|
||||||
this.canLoseLife = true;
|
this.canLoseLife = true;
|
||||||
this.canPayLifeCost = true;
|
this.canPayLifeCost = true;
|
||||||
|
@ -1386,6 +1390,16 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
||||||
this.maxHandSize = maxHandSize;
|
this.maxHandSize = maxHandSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMaxAttackedBy(int maxAttackedBy) {
|
||||||
|
this.maxAttackedBy = maxAttackedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxAttackedBy() {
|
||||||
|
return maxAttackedBy;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setResponseString(String responseString) {}
|
public void setResponseString(String responseString) {}
|
||||||
|
|
||||||
|
@ -1604,6 +1618,8 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param game
|
||||||
|
* @param appliedEffects
|
||||||
*
|
*
|
||||||
* @return true if player won the toss
|
* @return true if player won the toss
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -50,9 +50,10 @@ public interface Target extends Serializable {
|
||||||
void clearChosen();
|
void clearChosen();
|
||||||
boolean isNotTarget();
|
boolean isNotTarget();
|
||||||
|
|
||||||
// controlls if it will be checked, if the target can be targeted from source
|
/**
|
||||||
// true = check for protection
|
* controlls if it will be checked, if the target can be targeted from source
|
||||||
// false = do not check for protection
|
* @param notTarget true = check for protection, false = do not check for protection
|
||||||
|
*/
|
||||||
void setNotTarget(boolean notTarget);
|
void setNotTarget(boolean notTarget);
|
||||||
|
|
||||||
// methods for targets
|
// methods for targets
|
||||||
|
|
Loading…
Add table
Reference in a new issue