mirror of
https://github.com/magefree/mage.git
synced 2025-12-24 20:41:58 -08:00
Merge branch 'master' of https://github.com/magefree/mage
This commit is contained in:
commit
0ebd773caf
55 changed files with 28614 additions and 28269 deletions
|
|
@ -228,30 +228,62 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
for (ManaCost cost : this) {
|
||||
if (!cost.isPaid() && cost instanceof ColoredManaCost) {
|
||||
cost.assignPayment(game, ability, pool);
|
||||
if (pool.count() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ManaCost cost : this) {
|
||||
if (!cost.isPaid() && cost instanceof HybridManaCost) {
|
||||
cost.assignPayment(game, ability, pool);
|
||||
if (pool.count() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mono Hybrid mana costs
|
||||
// First try only to pay colored mana with the pool
|
||||
for (ManaCost cost : this) {
|
||||
if (!cost.isPaid() && cost instanceof MonoHybridManaCost) {
|
||||
if (((((MonoHybridManaCost) cost).containsColor(ColoredManaSymbol.W)) && pool.getWhite() > 0)
|
||||
|| ((((MonoHybridManaCost) cost).containsColor(ColoredManaSymbol.B)) && pool.getBlack() > 0)
|
||||
|| ((((MonoHybridManaCost) cost).containsColor(ColoredManaSymbol.R)) && pool.getRed() > 0)
|
||||
|| ((((MonoHybridManaCost) cost).containsColor(ColoredManaSymbol.G)) && pool.getGreen() > 0)
|
||||
|| ((((MonoHybridManaCost) cost).containsColor(ColoredManaSymbol.U)) && pool.getBlue() > 0)) {
|
||||
cost.assignPayment(game, ability, pool);
|
||||
if (pool.count() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if colored didn't fit pay colorless with the mana
|
||||
for (ManaCost cost : this) {
|
||||
if (!cost.isPaid() && cost instanceof MonoHybridManaCost) {
|
||||
cost.assignPayment(game, ability, pool);
|
||||
if (pool.count() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ManaCost cost : this) {
|
||||
if (!cost.isPaid() && cost instanceof SnowManaCost) {
|
||||
cost.assignPayment(game, ability, pool);
|
||||
if (pool.count() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ManaCost cost : this) {
|
||||
if (!cost.isPaid() && cost instanceof GenericManaCost) {
|
||||
cost.assignPayment(game, ability, pool);
|
||||
if (pool.count() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR
|
|||
if (targetName != null && targetName.length() > 0) {
|
||||
return targetName + " doesn't untap during its controller's next untap step";
|
||||
} else {
|
||||
return "Target " + (mode == null ? "creature" : mode.getTargets().get(0).getTargetName()) + " doesn't untap during its controller's next untap step";
|
||||
return "target " + (mode == null ? "creature" : mode.getTargets().get(0).getTargetName()) + " doesn't untap during its controller's next untap step";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -46,8 +45,7 @@ import mage.target.TargetPermanent;
|
|||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* All opponents have to sacrifice [amount] permanents
|
||||
* that match the [filter].
|
||||
* All opponents have to sacrifice [amount] permanents that match the [filter].
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
|
@ -59,6 +57,7 @@ public class SacrificeOpponentsEffect extends OneShotEffect {
|
|||
public SacrificeOpponentsEffect(FilterPermanent filter) {
|
||||
this(1, filter);
|
||||
}
|
||||
|
||||
public SacrificeOpponentsEffect(int amount, FilterPermanent filter) {
|
||||
this(new StaticValue(amount), filter);
|
||||
}
|
||||
|
|
@ -87,12 +86,14 @@ public class SacrificeOpponentsEffect extends OneShotEffect {
|
|||
filter.add(new ControllerPredicate(TargetController.YOU));
|
||||
for (UUID playerId : game.getOpponents(source.getControllerId())) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null) {
|
||||
if (player != null) {
|
||||
int numTargets = Math.min(amount.calculate(game, source, this), game.getBattlefield().countAll(filter, player.getId(), game));
|
||||
TargetPermanent target = new TargetPermanent(numTargets, numTargets, filter, true);
|
||||
if (target.canChoose(player.getId(), game)) {
|
||||
player.chooseTarget(Outcome.Sacrifice, target, source, game);
|
||||
perms.addAll(target.getTargets());
|
||||
if (numTargets > 0) {
|
||||
TargetPermanent target = new TargetPermanent(numTargets, numTargets, filter, true);
|
||||
if (target.canChoose(player.getId(), game)) {
|
||||
player.chooseTarget(Outcome.Sacrifice, target, source, game);
|
||||
perms.addAll(target.getTargets());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -12,6 +11,7 @@ import mage.constants.Duration;
|
|||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.watchers.common.AttackedThisTurnWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -24,19 +24,28 @@ public class AttacksIfAbleAllEffect extends RequirementEffect {
|
|||
public AttacksIfAbleAllEffect(FilterCreaturePermanent filter) {
|
||||
this(filter, Duration.WhileOnBattlefield);
|
||||
}
|
||||
|
||||
|
||||
boolean eachCombat;
|
||||
|
||||
public AttacksIfAbleAllEffect(FilterCreaturePermanent filter, Duration duration) {
|
||||
this(filter, duration, false);
|
||||
}
|
||||
|
||||
public AttacksIfAbleAllEffect(FilterCreaturePermanent filter, Duration duration, boolean eachCombat) {
|
||||
super(duration);
|
||||
staticText = new StringBuilder(filter.getMessage())
|
||||
.append(" attack ")
|
||||
.append(duration.equals(Duration.EndOfTurn) ? "this":"each")
|
||||
.append(" turn if able").toString();
|
||||
this.filter = filter;
|
||||
this.eachCombat = eachCombat;
|
||||
if (this.duration == Duration.EndOfTurn) {
|
||||
staticText = filter.getMessage() + " attack " + (eachCombat ? "each combat" : "this turn") + " if able";
|
||||
} else {
|
||||
staticText = filter.getMessage() + " attack each " + (eachCombat ? "combat" : "turn") + " if able";
|
||||
}
|
||||
}
|
||||
|
||||
public AttacksIfAbleAllEffect(final AttacksIfAbleAllEffect effect) {
|
||||
super(effect);
|
||||
this.filter = effect.filter;
|
||||
this.eachCombat = effect.eachCombat;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -46,7 +55,14 @@ public class AttacksIfAbleAllEffect extends RequirementEffect {
|
|||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
return filter.match(permanent, source.getSourceId(), source.getControllerId(), game);
|
||||
if (filter.match(permanent, source.getSourceId(), source.getControllerId(), game)) {
|
||||
if (eachCombat) {
|
||||
return true;
|
||||
}
|
||||
AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get("AttackedThisTurn");
|
||||
return watcher != null && !watcher.getAttackedThisTurnCreatures().contains(permanent.getId());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -25,13 +25,12 @@
|
|||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import mage.constants.Duration;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.RequirementEffect;
|
||||
import mage.constants.Duration;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
|
|
@ -56,10 +55,7 @@ public class AttacksIfAbleTargetEffect extends RequirementEffect {
|
|||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
if (this.getTargetPointer().getTargets(game, source).contains(permanent.getId())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return this.getTargetPointer().getTargets(game, source).contains(permanent.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -79,8 +75,7 @@ public class AttacksIfAbleTargetEffect extends RequirementEffect {
|
|||
}
|
||||
if (this.duration == Duration.EndOfTurn) {
|
||||
return new StringBuilder("Target ").append(mode.getTargets().get(0).getTargetName()).append(" attacks this turn if able").toString();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return new StringBuilder("Target ").append(mode.getTargets().get(0).getTargetName()).append(" attacks each turn if able").toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,10 @@ public abstract class ExpansionSet implements Serializable {
|
|||
protected String blockName;
|
||||
protected boolean hasBoosters = false;
|
||||
protected int numBoosterSpecial;
|
||||
|
||||
protected int numBoosterLands;
|
||||
protected int ratioBoosterSpecialLand = 0; // if > 0 basic lands are replaced with speical land in the ratio every X land is replaced by special land
|
||||
|
||||
protected int numBoosterCommon;
|
||||
protected int numBoosterUncommon;
|
||||
protected int numBoosterRare;
|
||||
|
|
@ -150,9 +153,14 @@ public abstract class ExpansionSet implements Serializable {
|
|||
}
|
||||
|
||||
if (numBoosterLands > 0) {
|
||||
List<CardInfo> specialLands = getSpecialLand();
|
||||
List<CardInfo> basicLands = getCardsByRarity(Rarity.LAND);
|
||||
for (int i = 0; i < numBoosterLands; i++) {
|
||||
addToBooster(booster, basicLands);
|
||||
if (ratioBoosterSpecialLand > 0 && rnd.nextInt(ratioBoosterSpecialLand) == 1 && specialLands != null) {
|
||||
addToBooster(booster, specialLands);
|
||||
} else {
|
||||
addToBooster(booster, basicLands);
|
||||
}
|
||||
}
|
||||
}
|
||||
List<CardInfo> commons = getCardsByRarity(Rarity.COMMON);
|
||||
|
|
@ -320,6 +328,10 @@ public abstract class ExpansionSet implements Serializable {
|
|||
return null;
|
||||
}
|
||||
|
||||
public List<CardInfo> getSpecialLand() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void removeSavedCards() {
|
||||
savedCards.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public enum CardRepository {
|
|||
// raise this if db structure was changed
|
||||
private static final long CARD_DB_VERSION = 41;
|
||||
// raise this if new cards were added to the server
|
||||
private static final long CARD_CONTENT_VERSION = 37;
|
||||
private static final long CARD_CONTENT_VERSION = 38;
|
||||
|
||||
private final Random random = new Random();
|
||||
private Dao<CardInfo, Object> cardDao;
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
|
|
@ -20,14 +20,14 @@
|
|||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.game.permanent.token;
|
||||
|
||||
import java.util.Random;
|
||||
import mage.MageInt;
|
||||
import mage.Mana;
|
||||
import mage.abilities.costs.common.SacrificeSourceCost;
|
||||
|
|
@ -49,7 +49,24 @@ public class EldraziScionToken extends Token {
|
|||
power = new MageInt(1);
|
||||
toughness = new MageInt(1);
|
||||
addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.ColorlessMana, new SacrificeSourceCost()));
|
||||
this.setOriginalExpansionSetCode("BFZ");
|
||||
setOriginalExpansionSetCode("BFZ");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpansionSetCodeForImage(String code) {
|
||||
super.setExpansionSetCodeForImage(code);
|
||||
if (getOriginalExpansionSetCode().equals("BFZ")) {
|
||||
this.setTokenType(new Random().nextInt(3) + 1); // 3 different images
|
||||
}
|
||||
}
|
||||
|
||||
public EldraziScionToken(final EldraziScionToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EldraziScionToken copy() {
|
||||
return new EldraziScionToken(this); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ public class Spell extends StackObjImpl implements Card {
|
|||
int index = 0;
|
||||
result = false;
|
||||
boolean legalParts = false;
|
||||
boolean notTargeted = true;
|
||||
// check for legal parts
|
||||
for (SpellAbility spellAbility : this.spellAbilities) {
|
||||
// if muliple modes are selected, and there are modes with targets, then at least one mode has to have a legal target or
|
||||
|
|
@ -178,10 +179,15 @@ public class Spell extends StackObjImpl implements Card {
|
|||
// If all targets are illegal when the spell tries to resolve, the spell is countered and none of its effects happen.
|
||||
// If at least one target is still legal at that time, the spell resolves, but an illegal target can't perform any actions
|
||||
// or have any actions performed on it.
|
||||
legalParts |= spellAbilityHasLegalParts(spellAbility, game);
|
||||
// if only a spliced spell has targets and all targets ar illegal, the complete spell is countered
|
||||
if (hasTargets(spellAbility, game)) {
|
||||
notTargeted = false;
|
||||
legalParts |= spellAbilityHasLegalParts(spellAbility, game);
|
||||
}
|
||||
|
||||
}
|
||||
// resolve if legal parts
|
||||
if (legalParts) {
|
||||
if (notTargeted || legalParts) {
|
||||
for (SpellAbility spellAbility : this.spellAbilities) {
|
||||
if (spellAbilityHasLegalParts(spellAbility, game)) {
|
||||
for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
|
||||
|
|
@ -262,6 +268,21 @@ public class Spell extends StackObjImpl implements Card {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean hasTargets(SpellAbility spellAbility, Game game) {
|
||||
if (spellAbility.getModes().getSelectedModes().size() > 1) {
|
||||
for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
|
||||
spellAbility.getModes().setActiveMode(modeId);
|
||||
if (!spellAbility.getTargets().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return !spellAbility.getTargets().isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean spellAbilityHasLegalParts(SpellAbility spellAbility, Game game) {
|
||||
if (spellAbility.getModes().getSelectedModes().size() > 1) {
|
||||
boolean targetedMode = false;
|
||||
|
|
|
|||
|
|
@ -2927,7 +2927,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
Set<Card> cardList = new HashSet<>();
|
||||
for (UUID cardId : cards) {
|
||||
fromZone = game.getState().getZone(cardId);
|
||||
if (fromZone.equals(Zone.BATTLEFIELD)) {
|
||||
if (Zone.BATTLEFIELD.equals(fromZone)) {
|
||||
Permanent permanent = game.getPermanent(cardId);
|
||||
if (permanent != null) {
|
||||
cardList.add(permanent);
|
||||
|
|
|
|||
|
|
@ -117,13 +117,15 @@ public class TargetSpellOrPermanent extends TargetImpl {
|
|||
if (permanent != null) {
|
||||
if (source != null) {
|
||||
MageObject targetSource = game.getObject(source.getSourceId());
|
||||
return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(permanent, source.getSourceId(), source.getControllerId(), game);
|
||||
return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game)
|
||||
&& filter.match(permanent, source.getSourceId(), source.getControllerId(), game);
|
||||
} else {
|
||||
return filter.match(permanent, game);
|
||||
}
|
||||
}
|
||||
Spell spell = game.getStack().getSpell(id);
|
||||
if (spell != null) {
|
||||
if (spell != null
|
||||
&& !source.getSourceId().equals(id)) { // 114.4. A spell or ability on the stack is an illegal target for itself.
|
||||
return filter.match(spell, game);
|
||||
}
|
||||
return false;
|
||||
|
|
@ -151,7 +153,9 @@ public class TargetSpellOrPermanent extends TargetImpl {
|
|||
MageObject targetSource = game.getObject(sourceId);
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
Spell spell = game.getStack().getSpell(stackObject.getId());
|
||||
if (spell != null && filter.match(spell, sourceId, sourceControllerId, game)) {
|
||||
if (spell != null
|
||||
&& !sourceId.equals(spell.getSourceId())
|
||||
&& filter.match(spell, sourceId, sourceControllerId, game)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
|
|
@ -184,7 +188,8 @@ public class TargetSpellOrPermanent extends TargetImpl {
|
|||
int count = 0;
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
Spell spell = game.getStack().getSpell(stackObject.getId());
|
||||
if (spell != null && filter.match(spell, null, sourceControllerId, game) && filter.match(spell, game)) {
|
||||
if (spell != null
|
||||
&& filter.match(spell, null, sourceControllerId, game) && filter.match(spell, game)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
|
|
@ -208,7 +213,9 @@ public class TargetSpellOrPermanent extends TargetImpl {
|
|||
MageObject targetSource = game.getObject(sourceId);
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
Spell spell = game.getStack().getSpell(stackObject.getId());
|
||||
if (spell != null && filter.match(spell, null, sourceControllerId, game) && filter.match(spell, game)) {
|
||||
if (spell != null
|
||||
&& !sourceId.equals(spell.getSourceId())
|
||||
&& filter.match(spell, sourceId, sourceControllerId, game)) {
|
||||
possibleTargets.add(spell.getId());
|
||||
}
|
||||
}
|
||||
|
|
@ -225,7 +232,8 @@ public class TargetSpellOrPermanent extends TargetImpl {
|
|||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
Spell spell = game.getStack().getSpell(stackObject.getId());
|
||||
if (spell != null && filter.match(spell, null, sourceControllerId, game) && filter.match(spell, game)) {
|
||||
if (spell != null
|
||||
&& filter.match(spell, null, sourceControllerId, game)) {
|
||||
possibleTargets.add(spell.getId());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue