forked from External/mage
Merge pull request 'master' (#24) from External/mage:master into master
Reviewed-on: #24
This commit is contained in:
commit
bbdd326d3a
148 changed files with 4758 additions and 1072 deletions
|
|
@ -16,24 +16,30 @@ import mage.util.CardUtil;
|
|||
public class PayMoreToCastAsThoughtItHadFlashAbility extends SpellAbility {
|
||||
|
||||
private final Cost costsToAdd;
|
||||
private final String rule;
|
||||
|
||||
public PayMoreToCastAsThoughtItHadFlashAbility(Card card, Cost costsToAdd) {
|
||||
this(card, costsToAdd, null);
|
||||
}
|
||||
|
||||
public PayMoreToCastAsThoughtItHadFlashAbility(Card card, Cost costsToAdd, String rule) {
|
||||
super(card.getSpellAbility().getManaCosts().copy(), card.getName(), Zone.HAND, SpellAbilityType.BASE_ALTERNATE);
|
||||
this.costsToAdd = costsToAdd;
|
||||
this.rule = rule;
|
||||
this.timing = TimingRule.INSTANT;
|
||||
this.setRuleAtTheTop(true);
|
||||
|
||||
if(costsToAdd instanceof ManaCosts<?>) {
|
||||
if (costsToAdd instanceof ManaCosts<?>) {
|
||||
ManaCosts<ManaCost> manaCosts = (ManaCosts<ManaCost>) costsToAdd;
|
||||
CardUtil.increaseCost(this, manaCosts);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.addCost(costsToAdd);
|
||||
}
|
||||
}
|
||||
|
||||
protected PayMoreToCastAsThoughtItHadFlashAbility(final PayMoreToCastAsThoughtItHadFlashAbility ability) {
|
||||
super(ability);
|
||||
this.rule = ability.rule;
|
||||
this.costsToAdd = ability.costsToAdd;
|
||||
}
|
||||
|
||||
|
|
@ -46,8 +52,12 @@ public class PayMoreToCastAsThoughtItHadFlashAbility extends SpellAbility {
|
|||
public String getRule(boolean all) {
|
||||
return getRule();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
if (rule != null && !rule.isEmpty()) {
|
||||
return rule;
|
||||
}
|
||||
if (costsToAdd instanceof ManaCosts) {
|
||||
return "You may cast {this} as though it had flash if you pay " + costsToAdd.getText() + " more to cast it. <i>(You may cast it any time you could cast an instant.)</i>";
|
||||
} else {
|
||||
|
|
@ -55,4 +65,4 @@ public class PayMoreToCastAsThoughtItHadFlashAbility extends SpellAbility {
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,23 +8,24 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public enum MultiAmountType {
|
||||
public class MultiAmountType {
|
||||
|
||||
MANA("Add mana", "Distribute mana among colors"),
|
||||
DAMAGE("Assign damage", "Assign damage among targets"),
|
||||
P1P1("Add +1/+1 counters", "Distribute +1/+1 counters among creatures"),
|
||||
COUNTERS("Choose counters", "Move counters"),
|
||||
CHEAT_LANDS("Choose lands", "Add lands to your battlefield", true);
|
||||
public static final MultiAmountType MANA = new MultiAmountType("Add mana", "Distribute mana among colors");
|
||||
public static final MultiAmountType DAMAGE = new MultiAmountType("Assign damage", "Assign damage among targets");
|
||||
|
||||
public static final MultiAmountType P1P1 = new MultiAmountType("Add +1/+1 counters", "Distribute +1/+1 counters among creatures");
|
||||
public static final MultiAmountType COUNTERS = new MultiAmountType("Choose counters", "Move counters");
|
||||
public static final MultiAmountType CHEAT_LANDS = new MultiAmountType("Choose lands", "Add lands to your battlefield", true);
|
||||
|
||||
private final String title;
|
||||
private final String header;
|
||||
private final boolean canCancel; // choice dialog will return null instead default values
|
||||
|
||||
MultiAmountType(String title, String header) {
|
||||
public MultiAmountType(String title, String header) {
|
||||
this(title, header, false);
|
||||
}
|
||||
|
||||
MultiAmountType(String title, String header, boolean canCancel) {
|
||||
public MultiAmountType(String title, String header, boolean canCancel) {
|
||||
this.title = title;
|
||||
this.header = header;
|
||||
this.canCancel = canCancel;
|
||||
|
|
@ -42,7 +43,7 @@ public enum MultiAmountType {
|
|||
return canCancel;
|
||||
}
|
||||
|
||||
public static List<Integer> prepareDefaltValues(List<MultiAmountMessage> constraints, int min, int max) {
|
||||
public static List<Integer> prepareDefaultValues(List<MultiAmountMessage> constraints, int min, int max) {
|
||||
// default values must be assigned from first to last by minimum values
|
||||
List<Integer> res = constraints.stream().map(m -> m.defaultValue > Integer.MIN_VALUE ? m.defaultValue : Math.min(0, max))
|
||||
.collect(Collectors.toList());
|
||||
|
|
@ -50,7 +51,7 @@ public enum MultiAmountType {
|
|||
return res;
|
||||
}
|
||||
|
||||
int total = res.stream().mapToInt(x -> x).sum();;
|
||||
int total = res.stream().mapToInt(x -> x).sum();
|
||||
|
||||
// Fill values until we reach the overall minimum. Do this by filling values up until either their max or however much is leftover, starting with the first option.
|
||||
if (min > 0 && total < min) {
|
||||
|
|
@ -174,7 +175,7 @@ public enum MultiAmountType {
|
|||
// data check
|
||||
if (returnDefaultOnError && !isGoodValues(res, constraints, min, max)) {
|
||||
// on broken data - return default
|
||||
return prepareDefaltValues(constraints, min, max);
|
||||
return prepareDefaultValues(constraints, min, max);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
|
||||
protected List<CombatGroup> groups = new ArrayList<>();
|
||||
protected List<CombatGroup> formerGroups = new ArrayList<>();
|
||||
protected Map<UUID, CombatGroup> blockingGroups = new HashMap<>();
|
||||
protected Map<UUID, CombatGroup> blockingGroups = new LinkedHashMap<>();
|
||||
// all possible defenders (players, planeswalkers or battle)
|
||||
protected Set<UUID> defenders = new HashSet<>();
|
||||
// how many creatures attack defending player
|
||||
|
|
@ -200,7 +200,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(attackingPlayerId).append(defenders);
|
||||
for (CombatGroup group : groups) {
|
||||
sb.append(group.defenderId).append(group.attackers).append(group.attackerOrder).append(group.blockers).append(group.blockerOrder);
|
||||
sb.append(group.defenderId).append(group.attackers).append(group.blockers);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
|
@ -785,7 +785,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
if (attackerExists) {
|
||||
if (!group.getBlockers().isEmpty()) {
|
||||
sb.append("blocked by ");
|
||||
for (UUID blockingCreatureId : group.getBlockerOrder()) {
|
||||
for (UUID blockingCreatureId : group.getBlockers()) {
|
||||
Permanent blockingCreature = game.getPermanent(blockingCreatureId);
|
||||
if (blockingCreature != null) {
|
||||
sb.append(blockingCreature.getLogName()).append(" (");
|
||||
|
|
@ -1799,24 +1799,11 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
return playerDefenders;
|
||||
}
|
||||
|
||||
public void damageAssignmentOrder(Game game) {
|
||||
for (CombatGroup group : groups) {
|
||||
group.pickBlockerOrder(attackingPlayerId, game);
|
||||
}
|
||||
for (Map.Entry<UUID, CombatGroup> blockingGroup : blockingGroups.entrySet()) {
|
||||
Permanent blocker = game.getPermanent(blockingGroup.getKey());
|
||||
if (blocker != null) {
|
||||
blockingGroup.getValue().pickAttackerOrder(blocker.getControllerId(), game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void removeAttacker(UUID attackerId, Game game) {
|
||||
for (CombatGroup group : groups) {
|
||||
if (group.attackers.contains(attackerId)) {
|
||||
group.attackers.remove(attackerId);
|
||||
group.attackerOrder.remove(attackerId);
|
||||
for (Set<UUID> attackingCreatures : numberCreaturesDefenderAttackedBy.values()) {
|
||||
attackingCreatures.remove(attackerId);
|
||||
}
|
||||
|
|
@ -1869,7 +1856,6 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
}
|
||||
for (CombatGroup group : groupsToCheck) {
|
||||
group.blockers.remove(blockerId);
|
||||
group.blockerOrder.remove(blockerId);
|
||||
if (group.blockers.isEmpty()) {
|
||||
group.blocked = false;
|
||||
}
|
||||
|
|
@ -1885,11 +1871,9 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
if (blockGroup.blockers.contains(blockerId)) {
|
||||
for (UUID attackerId : group.getAttackers()) {
|
||||
blockGroup.attackers.remove(attackerId);
|
||||
blockGroup.attackerOrder.remove(attackerId);
|
||||
}
|
||||
if (creature.getBlocking() == 0) {
|
||||
blockGroup.blockers.remove(blockerId);
|
||||
blockGroup.attackerOrder.clear();
|
||||
}
|
||||
}
|
||||
if (blockGroup.blockers.isEmpty()) {
|
||||
|
|
@ -1914,7 +1898,6 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
for (CombatGroup group : groups) {
|
||||
if (group.blockers.contains(blockerId)) {
|
||||
group.blockers.remove(blockerId);
|
||||
group.blockerOrder.remove(blockerId);
|
||||
if (group.blockers.isEmpty()) {
|
||||
group.blocked = false;
|
||||
}
|
||||
|
|
@ -1924,7 +1907,6 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
for (CombatGroup group : getBlockingGroups()) {
|
||||
if (group.blockers.contains(blockerId)) {
|
||||
group.blockers.remove(blockerId);
|
||||
group.attackerOrder.clear();
|
||||
}
|
||||
if (group.blockers.isEmpty()) {
|
||||
canRemove = true;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import mage.abilities.common.ControllerDivideCombatDamageAbility;
|
|||
import mage.abilities.common.DamageAsThoughNotBlockedAbility;
|
||||
import mage.abilities.keyword.*;
|
||||
import mage.constants.AsThoughEffectType;
|
||||
import mage.constants.MultiAmountType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
|
|
@ -15,6 +16,7 @@ import mage.game.events.GameEvent;
|
|||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.util.Copyable;
|
||||
import mage.util.MultiAmountMessage;
|
||||
import mage.watchers.common.FirstStrikeWatcher;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
|
@ -29,8 +31,6 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
protected List<UUID> attackers = new ArrayList<>();
|
||||
protected List<UUID> formerAttackers = new ArrayList<>();
|
||||
protected List<UUID> blockers = new ArrayList<>();
|
||||
protected List<UUID> blockerOrder = new ArrayList<>();
|
||||
protected List<UUID> attackerOrder = new ArrayList<>();
|
||||
protected Map<UUID, UUID> players = new HashMap<>();
|
||||
protected boolean blocked;
|
||||
protected UUID defenderId; // planeswalker, player, or battle id, can be null after remove from combat (e.g. due damage)
|
||||
|
|
@ -52,8 +52,6 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
this.attackers.addAll(group.attackers);
|
||||
this.formerAttackers.addAll(group.formerAttackers);
|
||||
this.blockers.addAll(group.blockers);
|
||||
this.blockerOrder.addAll(group.blockerOrder);
|
||||
this.attackerOrder.addAll(group.attackerOrder);
|
||||
this.players.putAll(group.players);
|
||||
this.blocked = group.blocked;
|
||||
this.defenderId = group.defenderId;
|
||||
|
|
@ -91,10 +89,6 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
return blockers;
|
||||
}
|
||||
|
||||
public List<UUID> getBlockerOrder() {
|
||||
return blockerOrder;
|
||||
}
|
||||
|
||||
private static boolean hasFirstOrDoubleStrike(Permanent perm) {
|
||||
return hasFirstStrike(perm) || hasDoubleStrike(perm);
|
||||
}
|
||||
|
|
@ -175,7 +169,6 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
if (attacker != null && !assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(attacker, attacker.getControllerId(), first, game, true)) {
|
||||
if (blockers.isEmpty()) {
|
||||
unblockedDamage(first, game);
|
||||
return;
|
||||
} else {
|
||||
Player player = game.getPlayer(defenderAssignsCombatDamage(game) ? defendingPlayerId : attacker.getControllerId());
|
||||
if ((attacker.getAbilities().containsKey(DamageAsThoughNotBlockedAbility.getInstance().getId()) &&
|
||||
|
|
@ -186,11 +179,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
blocked = false;
|
||||
unblockedDamage(first, game);
|
||||
}
|
||||
if (blockers.size() == 1) {
|
||||
singleBlockerDamage(player, first, game);
|
||||
} else {
|
||||
multiBlockerDamage(player, first, game);
|
||||
}
|
||||
blockerDamage(player, first, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -206,9 +195,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
}
|
||||
}
|
||||
if (attackers.size() != 1) {
|
||||
multiAttackerDamage(first, game);
|
||||
// } else {
|
||||
// singleAttackerDamage(first, game);
|
||||
attackerDamage(first, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -269,51 +256,16 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void singleBlockerDamage(Player player, boolean first, Game game) {
|
||||
Permanent blocker = game.getPermanent(blockers.get(0));
|
||||
Permanent attacker = game.getPermanent(attackers.get(0));
|
||||
if (blocker != null && attacker != null) {
|
||||
int blockerDamage = getDamageValueFromPermanent(blocker, game); // must be set before attacker damage marking because of effects like Test of Faith
|
||||
if (blocked && dealsDamageThisStep(attacker, first, game)) {
|
||||
int damage = getDamageValueFromPermanent(attacker, game);
|
||||
if (hasTrample(attacker)) {
|
||||
int lethalDamage = getLethalDamage(blocker, attacker, game);
|
||||
if (lethalDamage >= damage) {
|
||||
blocker.markDamage(damage, attacker.getId(), null, game, true, true);
|
||||
} else {
|
||||
int damageAssigned = player.getAmount(lethalDamage, damage, "Assign damage to " + blocker.getName(), game);
|
||||
blocker.markDamage(damageAssigned, attacker.getId(), null, game, true, true);
|
||||
damage -= damageAssigned;
|
||||
if (damage > 0) {
|
||||
defenderDamage(attacker, damage, game, false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
blocker.markDamage(damage, attacker.getId(), null, game, true, true);
|
||||
}
|
||||
}
|
||||
if (dealsDamageThisStep(blocker, first, game)) {
|
||||
if (checkSoleBlockerAfter(blocker, game)) { // blocking several creatures handled separately
|
||||
if (!assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(blocker, blocker.getControllerId(), first, game, false)) {
|
||||
attacker.markDamage(blockerDamage, blocker.getId(), null, game, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void multiBlockerDamage(Player player, boolean first, Game game) {
|
||||
private void blockerDamage(Player player, boolean first, Game game) {
|
||||
Permanent attacker = game.getPermanent(attackers.get(0));
|
||||
if (attacker == null) {
|
||||
return;
|
||||
}
|
||||
boolean oldRuleDamage = (Objects.equals(player.getId(), defendingPlayerId));
|
||||
int damage = getDamageValueFromPermanent(attacker, game);
|
||||
if (dealsDamageThisStep(attacker, first, game)) {
|
||||
// must be set before attacker damage marking because of effects like Test of Faith
|
||||
Map<UUID, Integer> blockerPower = new HashMap<>();
|
||||
for (UUID blockerId : blockerOrder) {
|
||||
for (UUID blockerId : blockers) {
|
||||
Permanent blocker = game.getPermanent(blockerId);
|
||||
if (dealsDamageThisStep(blocker, first, game)) {
|
||||
if (checkSoleBlockerAfter(blocker, game)) { // blocking several creatures handled separately
|
||||
|
|
@ -322,42 +274,62 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
}
|
||||
}
|
||||
Map<UUID, Integer> assigned = new HashMap<>();
|
||||
List<MultiAmountMessage> damageDivision = new ArrayList<>();
|
||||
List<UUID> blockersCopy = new ArrayList<>(blockers);
|
||||
if (blocked) {
|
||||
boolean excessDamageToDefender = true;
|
||||
for (UUID blockerId : new ArrayList<>(blockerOrder)) { // prevent ConcurrentModificationException
|
||||
int remainingDamage = damage;
|
||||
for (UUID blockerId : blockers) {
|
||||
Permanent blocker = game.getPermanent(blockerId);
|
||||
if (blocker != null) {
|
||||
int lethalDamage = getLethalDamage(blocker, attacker, game);
|
||||
if (lethalDamage >= damage) {
|
||||
if (!oldRuleDamage) {
|
||||
assigned.put(blockerId, damage);
|
||||
damage = 0;
|
||||
break;
|
||||
} else if (damage == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
int damageAssigned = 0;
|
||||
if (!oldRuleDamage) {
|
||||
damageAssigned = player.getAmount(lethalDamage, damage, "Assign damage to " + blocker.getName(), game);
|
||||
} else {
|
||||
damageAssigned = player.getAmount(0, damage, "Assign damage to " + blocker.getName(), game);
|
||||
if (damageAssigned < lethalDamage) {
|
||||
excessDamageToDefender = false; // all blockers need to have lethal damage assigned before it can trample over to the defender
|
||||
}
|
||||
}
|
||||
assigned.put(blockerId, damageAssigned);
|
||||
damage -= damageAssigned;
|
||||
int defaultDamage = Math.min(remainingDamage, blocker.getLethalDamage(attacker.getId(), game));
|
||||
remainingDamage -= defaultDamage;
|
||||
String message = String.format("%s, P/T: %d/%d",
|
||||
blocker.getLogName(),
|
||||
blocker.getPower().getValue(),
|
||||
blocker.getToughness().getValue());
|
||||
damageDivision.add(new MultiAmountMessage(message, 0, damage, defaultDamage));
|
||||
}
|
||||
}
|
||||
if (damage > 0 && hasTrample(attacker) && excessDamageToDefender) {
|
||||
defenderDamage(attacker, damage, game, false);
|
||||
} else if (!blockerOrder.isEmpty()) {
|
||||
// Assign the damage left to first blocker
|
||||
assigned.put(blockerOrder.get(0), assigned.get(blockerOrder.get(0)) == null ? 0 : assigned.get(blockerOrder.get(0)) + damage);
|
||||
List<Integer> amounts;
|
||||
if (hasTrample(attacker)){
|
||||
if (remainingDamage > 0 || damageDivision.size() > 1) {
|
||||
MultiAmountType dialogue = new MultiAmountType("Assign combat damage (with trample)",
|
||||
String.format("Assign combat damage among creatures blocking %s, P/T: %d/%d (Unassigned damage tramples through)",
|
||||
attacker.getLogName(), attacker.getPower().getValue(), attacker.getToughness().getValue()));
|
||||
amounts = player.getMultiAmountWithIndividualConstraints(Outcome.Damage, damageDivision, damage - remainingDamage, damage, dialogue, game);
|
||||
} else {
|
||||
amounts = new ArrayList<>();
|
||||
if (damageDivision.size() == 1) { // Assign all damage to one blocker
|
||||
amounts.add(damage);
|
||||
}
|
||||
}
|
||||
int trampleDamage = damage - (amounts.stream().mapToInt(x -> x).sum());
|
||||
if (trampleDamage > 0) {
|
||||
defenderDamage(attacker, trampleDamage, game, false);
|
||||
}
|
||||
} else {
|
||||
if (remainingDamage > 0){
|
||||
damageDivision.get(0).defaultValue += remainingDamage;
|
||||
}
|
||||
if (damageDivision.size() > 1) {
|
||||
MultiAmountType dialogue = new MultiAmountType("Assign combat damage",
|
||||
String.format("Assign combat damage among creatures blocking %s, P/T: %d/%d",
|
||||
attacker.getLogName(), attacker.getPower().getValue(), attacker.getToughness().getValue()));
|
||||
amounts = player.getMultiAmountWithIndividualConstraints(Outcome.Damage, damageDivision, damage, damage, dialogue, game);
|
||||
} else {
|
||||
amounts = new LinkedList<>();
|
||||
if (damageDivision.size() == 1) { // Assign all damage to one blocker
|
||||
amounts.add(damage);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!damageDivision.isEmpty()){
|
||||
for (int i=0; i<blockersCopy.size(); i++) {
|
||||
assigned.put(blockersCopy.get(i), amounts.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (UUID blockerId : blockerOrder) {
|
||||
for (UUID blockerId : blockers) {
|
||||
Integer power = blockerPower.get(blockerId);
|
||||
if (power != null) {
|
||||
// might be missing canDamage condition?
|
||||
|
|
@ -374,7 +346,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
for (UUID blockerId : blockerOrder) {
|
||||
for (UUID blockerId : blockers) {
|
||||
Permanent blocker = game.getPermanent(blockerId);
|
||||
if (dealsDamageThisStep(blocker, first, game)) {
|
||||
if (!assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(blocker, blocker.getControllerId(), first, game, false)) {
|
||||
|
|
@ -395,7 +367,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
if (dealsDamageThisStep(attacker, first, game)) {
|
||||
// must be set before attacker damage marking because of effects like Test of Faith
|
||||
Map<UUID, Integer> blockerPower = new HashMap<>();
|
||||
for (UUID blockerId : blockerOrder) {
|
||||
for (UUID blockerId : blockers) {
|
||||
Permanent blocker = game.getPermanent(blockerId);
|
||||
if (dealsDamageThisStep(blocker, first, game)) {
|
||||
if (checkSoleBlockerAfter(blocker, game)) { // blocking several creatures handled separately
|
||||
|
|
@ -422,7 +394,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
}
|
||||
}
|
||||
if (isAttacking) {
|
||||
for (UUID blockerId : blockerOrder) {
|
||||
for (UUID blockerId : blockers) {
|
||||
Integer power = blockerPower.get(blockerId);
|
||||
if (power != null) {
|
||||
// might be missing canDamage condition?
|
||||
|
|
@ -439,7 +411,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
}
|
||||
} else {
|
||||
if (isAttacking) {
|
||||
for (UUID blockerId : blockerOrder) {
|
||||
for (UUID blockerId : blockers) {
|
||||
Permanent blocker = game.getPermanent(blockerId);
|
||||
if (dealsDamageThisStep(blocker, first, game)) {
|
||||
if (!assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(blocker, blocker.getControllerId(), first, game, false)) {
|
||||
|
|
@ -473,81 +445,62 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
/**
|
||||
* Damages attacking creatures by a creature that blocked several ones
|
||||
* Damages only attackers as blocker was damage in
|
||||
* {@link #singleBlockerDamage}.
|
||||
* {@link #blockerDamage}.
|
||||
* <p>
|
||||
* Handles abilities like "{this} an block any number of creatures.".
|
||||
* <p>
|
||||
* Blocker damage for blockers blocking single creatures is handled in the
|
||||
* single/multi blocker methods, so this shouldn't be used anymore.
|
||||
*
|
||||
* @param first
|
||||
* @param game
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
private void singleAttackerDamage(boolean first, Game game) {
|
||||
Permanent blocker = game.getPermanent(blockers.get(0));
|
||||
Permanent attacker = game.getPermanent(attackers.get(0));
|
||||
if (blocker != null && attacker != null) {
|
||||
if (dealsDamageThisStep(blocker, first, game)) {
|
||||
int damage = getDamageValueFromPermanent(blocker, game);
|
||||
attacker.markDamage(damage, blocker.getId(), null, game, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Damages attacking creatures by a creature that blocked several ones
|
||||
* Damages only attackers as blocker was damage in either
|
||||
* {@link #singleBlockerDamage} or {@link #multiBlockerDamage}.
|
||||
* <p>
|
||||
* Handles abilities like "{this} an block any number of creatures.".
|
||||
* Handles abilities like "{this} can block any number of creatures.".
|
||||
*
|
||||
* @param first
|
||||
* @param game
|
||||
*/
|
||||
private void multiAttackerDamage(boolean first, Game game) {
|
||||
private void attackerDamage(boolean first, Game game) {
|
||||
Permanent blocker = game.getPermanent(blockers.get(0));
|
||||
if (blocker == null) {
|
||||
return;
|
||||
}
|
||||
boolean oldRuleDamage = attackerAssignsCombatDamage(game); // handles banding
|
||||
Player player = game.getPlayer(oldRuleDamage ? game.getCombat().getAttackingPlayerId() : blocker.getControllerId());
|
||||
//Handle Banding
|
||||
Player player = game.getPlayer(attackerAssignsCombatDamage(game) ? game.getCombat().getAttackingPlayerId() : blocker.getControllerId());
|
||||
int damage = getDamageValueFromPermanent(blocker, game);
|
||||
|
||||
if (dealsDamageThisStep(blocker, first, game)) {
|
||||
Map<UUID, Integer> assigned = new HashMap<>();
|
||||
for (UUID attackerId : attackerOrder) {
|
||||
List<MultiAmountMessage> damageDivision = new ArrayList<>();
|
||||
List<UUID> attackersCopy = new ArrayList<>(attackers);
|
||||
int remainingDamage = damage;
|
||||
for (UUID attackerId : attackers) {
|
||||
Permanent attacker = game.getPermanent(attackerId);
|
||||
if (attacker != null) {
|
||||
int lethalDamage = getLethalDamage(attacker, blocker, game);
|
||||
if (lethalDamage >= damage) {
|
||||
if (!oldRuleDamage) {
|
||||
assigned.put(attackerId, damage);
|
||||
damage = 0;
|
||||
break;
|
||||
} else if (damage == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
int damageAssigned = 0;
|
||||
if (!oldRuleDamage) {
|
||||
damageAssigned = player.getAmount(lethalDamage, damage, "Assign damage to " + attacker.getName(), game);
|
||||
} else {
|
||||
damageAssigned = player.getAmount(0, damage, "Assign damage to " + attacker.getName(), game);
|
||||
}
|
||||
assigned.put(attackerId, damageAssigned);
|
||||
damage -= damageAssigned;
|
||||
int defaultDamage = Math.min(remainingDamage, attacker.getLethalDamage(blocker.getId(), game));
|
||||
remainingDamage -= defaultDamage;
|
||||
String message = String.format("%s, P/T: %d/%d",
|
||||
attacker.getLogName(),
|
||||
attacker.getPower().getValue(),
|
||||
attacker.getToughness().getValue());
|
||||
damageDivision.add(new MultiAmountMessage(message, 0, damage, defaultDamage));
|
||||
}
|
||||
}
|
||||
if (damage > 0) {
|
||||
// Assign the damage left to first attacker
|
||||
assigned.put(attackerOrder.get(0), assigned.get(attackerOrder.get(0)) + damage);
|
||||
List<Integer> amounts;
|
||||
if (remainingDamage > 0){
|
||||
damageDivision.get(0).defaultValue += remainingDamage;
|
||||
}
|
||||
if (damageDivision.size() > 1) {
|
||||
MultiAmountType dialogue = new MultiAmountType("Assign blocker combat damage",
|
||||
String.format("Assign combat damage among creatures blocked by %s, P/T: %d/%d",
|
||||
blocker.getLogName(), blocker.getPower().getValue(), blocker.getToughness().getValue()));
|
||||
amounts = player.getMultiAmountWithIndividualConstraints(Outcome.Damage, damageDivision, damage, damage, dialogue, game);
|
||||
} else {
|
||||
amounts = new LinkedList<>();
|
||||
amounts.add(damage);
|
||||
}
|
||||
if (!damageDivision.isEmpty()){
|
||||
for (int i=0; i<attackersCopy.size(); i++) {
|
||||
assigned.put(attackersCopy.get(i), amounts.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<UUID, Integer> entry : assigned.entrySet()) {
|
||||
Permanent attacker = game.getPermanent(entry.getKey());
|
||||
attacker.markDamage(entry.getValue(), blocker.getId(), null, game, true, true);
|
||||
if (attacker != null) {
|
||||
attacker.markDamage(entry.getValue(), blocker.getId(), null, game, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -632,74 +585,11 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
if (blockerId != null && blocker != null) {
|
||||
blocker.setBlocking(blocker.getBlocking() + 1);
|
||||
blockers.add(blockerId);
|
||||
blockerOrder.add(blockerId);
|
||||
this.blocked = true;
|
||||
this.players.put(blockerId, playerId);
|
||||
}
|
||||
}
|
||||
|
||||
public void pickBlockerOrder(UUID playerId, Game game) {
|
||||
if (blockers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Player player = game.getPlayer(playerId); // game.getPlayer(defenderAssignsCombatDamage(game) ? defendingPlayerId : playerId); // this was incorrect because defenderAssignsCombatDamage might be false by the time damage is dealt
|
||||
List<UUID> blockerList = new ArrayList<>(blockers);
|
||||
blockerOrder.clear();
|
||||
while (player.canRespond()) {
|
||||
if (blockerList.size() == 1) {
|
||||
blockerOrder.add(blockerList.get(0));
|
||||
break;
|
||||
} else {
|
||||
List<Permanent> blockerPerms = new ArrayList<>();
|
||||
for (UUID blockerId : blockerList) {
|
||||
blockerPerms.add(game.getPermanent(blockerId));
|
||||
}
|
||||
UUID blockerId = player.chooseBlockerOrder(blockerPerms, this, blockerOrder, game);
|
||||
blockerOrder.add(blockerId);
|
||||
blockerList.remove(blockerId);
|
||||
}
|
||||
}
|
||||
if (!game.isSimulation() && blockerOrder.size() > 1) {
|
||||
logDamageAssignmentOrder("Creatures blocking ", attackers, blockerOrder, game);
|
||||
}
|
||||
}
|
||||
|
||||
public void pickAttackerOrder(UUID playerId, Game game) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (attackers.isEmpty() || player == null) {
|
||||
return;
|
||||
}
|
||||
List<UUID> attackerList = new ArrayList<>(attackers);
|
||||
List<UUID> newAttackerOrder = new ArrayList<>();
|
||||
while (true) {
|
||||
if (attackerList.size() == 1) {
|
||||
newAttackerOrder.add(attackerList.get(0));
|
||||
break;
|
||||
} else {
|
||||
List<Permanent> attackerPerms = new ArrayList<>();
|
||||
for (UUID attackerId : attackerList) {
|
||||
attackerPerms.add(game.getPermanent(attackerId));
|
||||
}
|
||||
UUID attackerId = player.chooseAttackerOrder(attackerPerms, game);
|
||||
if (attackerId == null) {
|
||||
break;
|
||||
}
|
||||
newAttackerOrder.add(attackerId);
|
||||
attackerList.remove(attackerId);
|
||||
}
|
||||
}
|
||||
if (attackerOrder.isEmpty() || newAttackerOrder.size() == attackerOrder.size()) {
|
||||
attackerOrder.clear();
|
||||
attackerOrder.addAll(newAttackerOrder);
|
||||
|
||||
if (!game.isSimulation() && attackerOrder.size() > 1) {
|
||||
logDamageAssignmentOrder("Creatures blocked by ", blockers, attackerOrder, game);
|
||||
}
|
||||
} else {
|
||||
game.informPlayers(player.getLogName() + " try to skip choose attacker order");
|
||||
}
|
||||
}
|
||||
|
||||
private void logDamageAssignmentOrder(String prefix, List<UUID> assignedFor, List<UUID> assignedOrder, Game game) {
|
||||
StringBuilder sb = new StringBuilder(prefix);
|
||||
boolean first = true;
|
||||
|
|
@ -746,12 +636,9 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
formerAttackers.add(creatureId);
|
||||
attackers.remove(creatureId);
|
||||
result = true;
|
||||
attackerOrder.remove(creatureId);
|
||||
} else if (blockers.contains(creatureId)) {
|
||||
blockers.remove(creatureId);
|
||||
result = true;
|
||||
//20100423 - 509.2a
|
||||
blockerOrder.remove(creatureId);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -825,7 +712,6 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
game.getCombat().removeBlocker(blockerId, game);
|
||||
}
|
||||
blockers.clear();
|
||||
blockerOrder.clear();
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(attacker.getLogName() + " can't be blocked except by " + attacker.getMinBlockedBy() + " or more creatures. Blockers discarded.");
|
||||
}
|
||||
|
|
@ -844,7 +730,6 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
game.getCombat().removeBlocker(blockerId, game);
|
||||
}
|
||||
blockers.clear();
|
||||
blockerOrder.clear();
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(new StringBuilder(attacker.getLogName())
|
||||
.append(" can't be blocked by more than ").append(attacker.getMaxBlockedBy())
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class CrushOfTentaclesToken extends TokenImpl {
|
||||
|
||||
public CrushOfTentaclesToken() {
|
||||
super("Octopus Token", "8/8 blue Octopus creature");
|
||||
this.cardType.add(CardType.CREATURE);
|
||||
this.color.setBlue(true);
|
||||
this.subtype.add(SubType.OCTOPUS);
|
||||
this.power = new MageInt(8);
|
||||
this.toughness = new MageInt(8);
|
||||
}
|
||||
|
||||
private CrushOfTentaclesToken(final CrushOfTentaclesToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public CrushOfTentaclesToken copy() {
|
||||
return new CrushOfTentaclesToken(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ import mage.constants.SubType;
|
|||
public final class DinDragonToken extends TokenImpl {
|
||||
|
||||
public DinDragonToken() {
|
||||
super("Dragon Token", "4/4 red Dinosaur Dragon creature token with flying");
|
||||
super("Dinosaur Dragon Token", "4/4 red Dinosaur Dragon creature token with flying");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setRed(true);
|
||||
subtype.add(SubType.DINOSAUR);
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ import mage.constants.SubType;
|
|||
/**
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class EyesOfTheWisentElementalToken extends TokenImpl {
|
||||
public final class Elemental44GreenToken extends TokenImpl {
|
||||
|
||||
public EyesOfTheWisentElementalToken() {
|
||||
public Elemental44GreenToken() {
|
||||
super("Elemental Token", "4/4 green Elemental creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setGreen(true);
|
||||
|
|
@ -18,11 +18,11 @@ public final class EyesOfTheWisentElementalToken extends TokenImpl {
|
|||
toughness = new MageInt(4);
|
||||
}
|
||||
|
||||
private EyesOfTheWisentElementalToken(final EyesOfTheWisentElementalToken token) {
|
||||
private Elemental44GreenToken(final Elemental44GreenToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public EyesOfTheWisentElementalToken copy() {
|
||||
return new EyesOfTheWisentElementalToken(this);
|
||||
public Elemental44GreenToken copy() {
|
||||
return new Elemental44GreenToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -7,13 +7,13 @@ import mage.constants.SubType;
|
|||
/**
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class SeedGuardianToken extends TokenImpl {
|
||||
public final class ElementalXXGreenToken extends TokenImpl {
|
||||
|
||||
public SeedGuardianToken() {
|
||||
public ElementalXXGreenToken() {
|
||||
this(1);
|
||||
}
|
||||
|
||||
public SeedGuardianToken(int xValue) {
|
||||
public ElementalXXGreenToken(int xValue) {
|
||||
super("Elemental Token", "X/X green Elemental creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setGreen(true);
|
||||
|
|
@ -22,11 +22,11 @@ public final class SeedGuardianToken extends TokenImpl {
|
|||
toughness = new MageInt(xValue);
|
||||
}
|
||||
|
||||
private SeedGuardianToken(final SeedGuardianToken token) {
|
||||
private ElementalXXGreenToken(final ElementalXXGreenToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public SeedGuardianToken copy() {
|
||||
return new SeedGuardianToken(this);
|
||||
public ElementalXXGreenToken copy() {
|
||||
return new ElementalXXGreenToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class GrovetenderDruidsPlantToken extends TokenImpl {
|
||||
|
||||
public GrovetenderDruidsPlantToken() {
|
||||
super("Plant Token", "1/1 green Plant creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setGreen(true);
|
||||
subtype.add(SubType.PLANT);
|
||||
power = new MageInt(1);
|
||||
toughness = new MageInt(1);
|
||||
}
|
||||
|
||||
private GrovetenderDruidsPlantToken(final GrovetenderDruidsPlantToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public GrovetenderDruidsPlantToken copy() {
|
||||
return new GrovetenderDruidsPlantToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -7,13 +7,13 @@ import mage.constants.SubType;
|
|||
/**
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class FleshCarverHorrorToken extends TokenImpl {
|
||||
public final class HorrorXXBlackToken extends TokenImpl {
|
||||
|
||||
public FleshCarverHorrorToken() {
|
||||
public HorrorXXBlackToken() {
|
||||
this(1);
|
||||
}
|
||||
|
||||
public FleshCarverHorrorToken(int xValue) {
|
||||
public HorrorXXBlackToken(int xValue) {
|
||||
super("Horror Token", "X/X black Horror creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setBlack(true);
|
||||
|
|
@ -22,11 +22,11 @@ public final class FleshCarverHorrorToken extends TokenImpl {
|
|||
toughness = new MageInt(xValue);
|
||||
}
|
||||
|
||||
private FleshCarverHorrorToken(final FleshCarverHorrorToken token) {
|
||||
private HorrorXXBlackToken(final HorrorXXBlackToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public FleshCarverHorrorToken copy() {
|
||||
return new FleshCarverHorrorToken(this);
|
||||
public HorrorXXBlackToken copy() {
|
||||
return new HorrorXXBlackToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ import mage.constants.SubType;
|
|||
public final class HumanRogueToken extends TokenImpl {
|
||||
|
||||
public HumanRogueToken() {
|
||||
super("Human Token", "1/1 white Human Rogue creature token");
|
||||
super("Human Rogue Token", "1/1 white Human Rogue creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setWhite(true);
|
||||
subtype.add(SubType.HUMAN);
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
|
||||
|
||||
package mage.game.permanent.token;
|
||||
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.MageInt;
|
||||
|
||||
/**
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class MarathWillOfTheWildElementalToken extends TokenImpl {
|
||||
|
||||
public MarathWillOfTheWildElementalToken() {
|
||||
super("Elemental Token", "X/X green Elemental creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
subtype.add(SubType.ELEMENTAL);
|
||||
color.setGreen(true);
|
||||
power = new MageInt(0);
|
||||
toughness = new MageInt(0);
|
||||
}
|
||||
|
||||
private MarathWillOfTheWildElementalToken(final MarathWillOfTheWildElementalToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public MarathWillOfTheWildElementalToken copy() {
|
||||
return new MarathWillOfTheWildElementalToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -5,25 +5,20 @@ import mage.constants.CardType;
|
|||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* @author FenrisulfrX
|
||||
* @author Quercitron
|
||||
*/
|
||||
public final class MinionToken extends TokenImpl {
|
||||
|
||||
public MinionToken() {
|
||||
this("DDE");
|
||||
}
|
||||
|
||||
public MinionToken(String setCode) {
|
||||
super("Phyrexian Minion Token", "X/X black Phyrexian Minion creature token");
|
||||
super("Minion Token", "1/1 black Minion creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
subtype.add(SubType.PHYREXIAN);
|
||||
subtype.add(SubType.MINION);
|
||||
color.setBlack(true);
|
||||
power = new MageInt(0);
|
||||
toughness = new MageInt(0);
|
||||
power = new MageInt(1);
|
||||
toughness = new MageInt(1);
|
||||
}
|
||||
|
||||
private MinionToken(final MinionToken token) {
|
||||
protected MinionToken(final MinionToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* @author Quercitron
|
||||
*/
|
||||
public final class MinionToken2 extends TokenImpl {
|
||||
|
||||
public MinionToken2() {
|
||||
super("Minion Token", "1/1 black Minion creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
subtype.add(SubType.MINION);
|
||||
color.setBlack(true);
|
||||
power = new MageInt(1);
|
||||
toughness = new MageInt(1);
|
||||
}
|
||||
|
||||
protected MinionToken2(final MinionToken2 token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public MinionToken2 copy() {
|
||||
return new MinionToken2(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
|
||||
|
||||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.target.common.TargetCardInGraveyard;
|
||||
|
||||
/**
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class NighteyesTheDesecratorToken extends TokenImpl {
|
||||
|
||||
public NighteyesTheDesecratorToken() {
|
||||
super("Nighteyes the Desecrator Token", "");
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setBlack(true);
|
||||
subtype.add(SubType.RAT);
|
||||
subtype.add(SubType.WIZARD);
|
||||
power = new MageInt(4);
|
||||
toughness = new MageInt(2);
|
||||
// {4}{B}: Put target creature card from a graveyard onto the battlefield under your control.
|
||||
Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl<>("{4}{B}"));
|
||||
ability.addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE_A_GRAVEYARD));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
private NighteyesTheDesecratorToken(final NighteyesTheDesecratorToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public NighteyesTheDesecratorToken copy() {
|
||||
return new NighteyesTheDesecratorToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* @author PurpleCrowbar
|
||||
*/
|
||||
public final class NoFlyingSpiritWhiteToken extends TokenImpl {
|
||||
|
||||
public NoFlyingSpiritWhiteToken() {
|
||||
super("Spirit Token", "1/1 white Spirit creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
subtype.add(SubType.SPIRIT);
|
||||
color.setWhite(true);
|
||||
power = new MageInt(1);
|
||||
toughness = new MageInt(1);
|
||||
}
|
||||
|
||||
private NoFlyingSpiritWhiteToken(final NoFlyingSpiritWhiteToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoFlyingSpiritWhiteToken copy() {
|
||||
return new NoFlyingSpiritWhiteToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* @author FenrisulfrX
|
||||
*/
|
||||
public final class PhyrexianMinionToken extends TokenImpl {
|
||||
|
||||
public PhyrexianMinionToken() {
|
||||
this(1);
|
||||
}
|
||||
|
||||
public PhyrexianMinionToken(int xValue) {
|
||||
super("Phyrexian Minion Token", "X/X black Phyrexian Minion creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
subtype.add(SubType.PHYREXIAN);
|
||||
subtype.add(SubType.MINION);
|
||||
color.setBlack(true);
|
||||
power = new MageInt(xValue);
|
||||
toughness = new MageInt(xValue);
|
||||
}
|
||||
|
||||
private PhyrexianMinionToken(final PhyrexianMinionToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public PhyrexianMinionToken copy() {
|
||||
return new PhyrexianMinionToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,9 +4,12 @@ import mage.MageInt;
|
|||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
public final class GrismoldPlantToken extends TokenImpl {
|
||||
/**
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class Plant11Token extends TokenImpl {
|
||||
|
||||
public GrismoldPlantToken() {
|
||||
public Plant11Token() {
|
||||
super("Plant Token", "1/1 green Plant creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setGreen(true);
|
||||
|
|
@ -15,11 +18,11 @@ public final class GrismoldPlantToken extends TokenImpl {
|
|||
toughness = new MageInt(1);
|
||||
}
|
||||
|
||||
private GrismoldPlantToken(final GrismoldPlantToken token) {
|
||||
private Plant11Token(final Plant11Token token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public GrismoldPlantToken copy() {
|
||||
return new GrismoldPlantToken(this);
|
||||
public Plant11Token copy() {
|
||||
return new Plant11Token(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
|
||||
package mage.game.permanent.token;
|
||||
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.MageInt;
|
||||
|
||||
/**
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class RallyTheHordeWarriorToken extends TokenImpl {
|
||||
|
||||
public RallyTheHordeWarriorToken() {
|
||||
super("Warrior Token", "1/1 red Warrior creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setRed(true);
|
||||
subtype.add(SubType.WARRIOR);
|
||||
power = new MageInt(1);
|
||||
toughness = new MageInt(1);
|
||||
}
|
||||
|
||||
private RallyTheHordeWarriorToken(final RallyTheHordeWarriorToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public RallyTheHordeWarriorToken copy() {
|
||||
return new RallyTheHordeWarriorToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* @author PurpleCrowbar
|
||||
*/
|
||||
public final class Soldier22Token extends TokenImpl {
|
||||
|
||||
public Soldier22Token() {
|
||||
super("Soldier Token", "2/2 white Soldier creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setWhite(true);
|
||||
subtype.add(SubType.SOLDIER);
|
||||
power = new MageInt(2);
|
||||
toughness = new MageInt(2);
|
||||
}
|
||||
|
||||
private Soldier22Token(final Soldier22Token token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Soldier22Token copy() {
|
||||
return new Soldier22Token(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class SorinSolemnVisitorVampireToken extends TokenImpl {
|
||||
|
||||
public SorinSolemnVisitorVampireToken() {
|
||||
super("Vampire Token", "2/2 black Vampire creature token with flying");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setBlack(true);
|
||||
subtype.add(SubType.VAMPIRE);
|
||||
power = new MageInt(2);
|
||||
toughness = new MageInt(2);
|
||||
addAbility(FlyingAbility.getInstance());
|
||||
}
|
||||
|
||||
private SorinSolemnVisitorVampireToken(final SorinSolemnVisitorVampireToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public SorinSolemnVisitorVampireToken copy() {
|
||||
return new SorinSolemnVisitorVampireToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class SpoilsOfBloodHorrorToken extends TokenImpl {
|
||||
|
||||
public SpoilsOfBloodHorrorToken() {
|
||||
this(1);
|
||||
}
|
||||
|
||||
public SpoilsOfBloodHorrorToken(int xValue) {
|
||||
super("Horror Token", "X/X black Horror creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setBlack(true);
|
||||
subtype.add(SubType.HORROR);
|
||||
power = new MageInt(xValue);
|
||||
toughness = new MageInt(xValue);
|
||||
}
|
||||
|
||||
private SpoilsOfBloodHorrorToken(final SpoilsOfBloodHorrorToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public SpoilsOfBloodHorrorToken copy() {
|
||||
return new SpoilsOfBloodHorrorToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* @author spjspj
|
||||
*/
|
||||
|
||||
public final class WalkerOfTheGroveToken extends TokenImpl {
|
||||
|
||||
public WalkerOfTheGroveToken() {
|
||||
super("Elemental Token", "4/4 green Elemental creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
this.subtype.add(SubType.ELEMENTAL);
|
||||
this.color.setGreen(true);
|
||||
power = new MageInt(4);
|
||||
toughness = new MageInt(4);
|
||||
}
|
||||
|
||||
private WalkerOfTheGroveToken(final WalkerOfTheGroveToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public WalkerOfTheGroveToken copy() {
|
||||
return new WalkerOfTheGroveToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
|
||||
package mage.game.turn;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
|
@ -37,7 +37,6 @@ public class DeclareBlockersStep extends Step {
|
|||
game.getCombat().selectBlockers(game);
|
||||
if (!game.isPaused() && !game.executingRollback()) {
|
||||
game.getCombat().acceptBlockers(game);
|
||||
game.getCombat().damageAssignmentOrder(game);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -46,7 +45,6 @@ public class DeclareBlockersStep extends Step {
|
|||
super.resumeBeginStep(game, activePlayerId);
|
||||
game.getCombat().resumeSelectBlockers(game);
|
||||
game.getCombat().acceptBlockers(game);
|
||||
game.getCombat().damageAssignmentOrder(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import mage.filter.FilterCard;
|
|||
import mage.filter.FilterMana;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.game.*;
|
||||
import mage.game.combat.CombatGroup;
|
||||
import mage.game.draft.Draft;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.match.Match;
|
||||
|
|
@ -761,19 +760,6 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
|
||||
void selectBlockers(Ability source, Game game, UUID defendingPlayerId);
|
||||
|
||||
UUID chooseAttackerOrder(List<Permanent> attacker, Game game);
|
||||
|
||||
/**
|
||||
* Choose the order in which blockers get damage assigned to
|
||||
*
|
||||
* @param blockers list of blockers where to choose the next one from
|
||||
* @param combatGroup the concerning combat group
|
||||
* @param blockerOrder the already set order of blockers
|
||||
* @param game
|
||||
* @return blocker next to add to the blocker order
|
||||
*/
|
||||
UUID chooseBlockerOrder(List<Permanent> blockers, CombatGroup combatGroup, List<UUID> blockerOrder, Game game);
|
||||
|
||||
int getAmount(int min, int max, String message, Game game);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -18,10 +18,8 @@ import mage.constants.Outcome;
|
|||
import mage.constants.RangeOfInfluence;
|
||||
import mage.filter.FilterMana;
|
||||
import mage.game.Game;
|
||||
import mage.game.combat.CombatGroup;
|
||||
import mage.game.draft.Draft;
|
||||
import mage.game.match.Match;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.tournament.Tournament;
|
||||
import mage.target.Target;
|
||||
import mage.target.TargetAmount;
|
||||
|
|
@ -190,16 +188,6 @@ public class StubPlayer extends PlayerImpl {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID chooseAttackerOrder(List<Permanent> attacker, Game game) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID chooseBlockerOrder(List<Permanent> blockers, CombatGroup combatGroup, List<UUID> blockerOrder, Game game) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAmount(int min, int max, String message, Game game) {
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue