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.git
This commit is contained in:
commit
2a2df685a9
140 changed files with 6263 additions and 268 deletions
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import java.util.UUID;
|
||||
|
|
@ -102,7 +101,10 @@ public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever a " + filter.getMessage() + " attacks" + (attacksYouOrYourPlaneswalker ? " you or a planeswalker you control" : "") + ", " + super.getRule();
|
||||
return "Whenever " + (filter.getMessage().startsWith("an") ? "" : "a ")
|
||||
+ filter.getMessage() + " attacks"
|
||||
+ (attacksYouOrYourPlaneswalker ? " you or a planeswalker you control" : "")
|
||||
+ ", " + super.getRule();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package mage.abilities.common;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
|
|
@ -11,8 +12,8 @@ import mage.game.Game;
|
|||
import mage.game.events.DamagedPlayerEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -20,22 +21,25 @@ import mage.game.permanent.Permanent;
|
|||
*/
|
||||
public class ControlledCreaturesDealCombatDamagePlayerTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private boolean madeDamage = false;
|
||||
private Set<UUID> damagedPlayerIds = new HashSet<>();
|
||||
private boolean setTargetPointer;
|
||||
|
||||
public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Effect effect) {
|
||||
this(Zone.BATTLEFIELD, effect);
|
||||
}
|
||||
|
||||
public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Zone zone, Effect effect) {
|
||||
this(zone, effect, false);
|
||||
}
|
||||
|
||||
public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Zone zone, Effect effect, boolean setTargetPointer) {
|
||||
super(zone, effect, false);
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
}
|
||||
|
||||
public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(final ControlledCreaturesDealCombatDamagePlayerTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.madeDamage = ability.madeDamage;
|
||||
this.damagedPlayerIds = new HashSet<>();
|
||||
this.damagedPlayerIds.addAll(ability.damagedPlayerIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -55,28 +59,19 @@ public class ControlledCreaturesDealCombatDamagePlayerTriggeredAbility extends T
|
|||
if (event.getType() == EventType.DAMAGED_PLAYER) {
|
||||
DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event;
|
||||
Permanent p = game.getPermanent(event.getSourceId());
|
||||
if (damageEvent.isCombatDamage() && p != null && p.isControlledBy(this.getControllerId())) {
|
||||
madeDamage = true;
|
||||
if (damageEvent.isCombatDamage() && p != null && p.isControlledBy(this.getControllerId()) && !damagedPlayerIds.contains(event.getPlayerId())) {
|
||||
damagedPlayerIds.add(event.getPlayerId());
|
||||
}
|
||||
}
|
||||
if (event.getType() == EventType.COMBAT_DAMAGE_STEP_PRIORITY) {
|
||||
if (madeDamage) {
|
||||
Set<UUID> damagedPlayersCopy = new HashSet<>();
|
||||
damagedPlayersCopy.addAll(damagedPlayerIds);
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setValue("damagedPlayers", damagedPlayersCopy);
|
||||
if (setTargetPointer) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(event.getPlayerId()));
|
||||
}
|
||||
}
|
||||
damagedPlayerIds.clear();
|
||||
madeDamage = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (event.getType() == EventType.ZONE_CHANGE && event.getTargetId().equals(getSourceId())) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
if (zEvent.getFromZone() == Zone.GRAVEYARD) {
|
||||
damagedPlayerIds.clear();
|
||||
}
|
||||
if (event.getType() == EventType.COMBAT_DAMAGE_STEP_PRIORITY ||
|
||||
(event.getType() == EventType.ZONE_CHANGE && event.getTargetId().equals(getSourceId()))) {
|
||||
damagedPlayerIds.clear();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public class ManaSpentToCastCount implements DynamicValue {
|
|||
}
|
||||
if (spell != null) {
|
||||
// NOT the cmc of the spell on the stack
|
||||
return spell.getSpellAbility().getManaCostsToPay().convertedManaCost() + spell.getSpellAbility().getManaCostsToPay().getX();
|
||||
return spell.getSpellAbility().getManaCostsToPay().convertedManaCost();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -8,6 +7,8 @@ import mage.MageObject;
|
|||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
|
||||
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
|
|
@ -17,6 +18,7 @@ import mage.constants.CardType;
|
|||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.token.EmptyToken;
|
||||
|
|
@ -124,14 +126,6 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
|
|||
this.isntLegendary = effect.isntLegendary;
|
||||
}
|
||||
|
||||
public void setBecomesArtifact(boolean becomesArtifact) {
|
||||
this.becomesArtifact = becomesArtifact;
|
||||
}
|
||||
|
||||
public void setIsntLegendary(boolean isntLegendary) {
|
||||
this.isntLegendary = isntLegendary;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
UUID targetId;
|
||||
|
|
@ -282,4 +276,33 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
|
|||
public void setUseLKI(boolean useLKI) {
|
||||
this.useLKI = useLKI;
|
||||
}
|
||||
|
||||
public void setBecomesArtifact(boolean becomesArtifact) {
|
||||
this.becomesArtifact = becomesArtifact;
|
||||
}
|
||||
|
||||
public void setIsntLegendary(boolean isntLegendary) {
|
||||
this.isntLegendary = isntLegendary;
|
||||
}
|
||||
|
||||
public void setHasHaste(boolean hasHaste) {
|
||||
this.hasHaste = hasHaste;
|
||||
}
|
||||
|
||||
public void exileTokensCreatedAtNextEndStep(Game game, Ability source) {
|
||||
for (Permanent tokenPermanent : addedTokenPermanents) {
|
||||
ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD);
|
||||
exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game));
|
||||
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source);
|
||||
}
|
||||
}
|
||||
|
||||
public void exileTokensCreatedAtEndOfCombat(Game game, Ability source) {
|
||||
for (Permanent tokenPermanent : addedTokenPermanents) {
|
||||
|
||||
ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD);
|
||||
exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game));
|
||||
game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect), source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
package mage.abilities.effects.common.continuous;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.common.ChooseCreatureTypeEffect;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
public class AddChosenSubtypeEffect extends ContinuousEffectImpl {
|
||||
|
||||
public AddChosenSubtypeEffect() {
|
||||
super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
|
||||
staticText = "{this} is the chosen type in addition to its other types";
|
||||
}
|
||||
|
||||
public AddChosenSubtypeEffect(final AddChosenSubtypeEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent != null) {
|
||||
SubType subType = ChooseCreatureTypeEffect.getChoosenCreatureType(permanent.getId(), game);
|
||||
if (subType != null && !permanent.hasSubtype(subType, game)) {
|
||||
permanent.getSubtype(game).add(subType);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddChosenSubtypeEffect copy() {
|
||||
return new AddChosenSubtypeEffect(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.effects.common.continuous;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -16,13 +15,24 @@ import mage.game.permanent.Permanent;
|
|||
*/
|
||||
public class SetPowerToughnessEnchantedEffect extends ContinuousEffectImpl {
|
||||
|
||||
private final int power;
|
||||
private final int toughness;
|
||||
|
||||
public SetPowerToughnessEnchantedEffect() {
|
||||
this(0, 2);
|
||||
}
|
||||
|
||||
public SetPowerToughnessEnchantedEffect(int power, int toughness) {
|
||||
super(Duration.WhileOnBattlefield, Layer.PTChangingEffects_7, SubLayer.SetPT_7b, Outcome.BoostCreature);
|
||||
staticText = "Enchanted creature has base power and toughness 0/2";
|
||||
staticText = "Enchanted creature has base power and toughness " + power + "/" + toughness;
|
||||
this.power = power;
|
||||
this.toughness = toughness;
|
||||
}
|
||||
|
||||
public SetPowerToughnessEnchantedEffect(final SetPowerToughnessEnchantedEffect effect) {
|
||||
super(effect);
|
||||
this.power = effect.power;
|
||||
this.toughness = effect.toughness;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -36,8 +46,8 @@ public class SetPowerToughnessEnchantedEffect extends ContinuousEffectImpl {
|
|||
if (enchantment != null && enchantment.getAttachedTo() != null) {
|
||||
Permanent enchanted = game.getPermanent(enchantment.getAttachedTo());
|
||||
if (enchanted != null) {
|
||||
enchanted.getPower().setValue(0);
|
||||
enchanted.getToughness().setValue(2);
|
||||
enchanted.getPower().setValue(power);
|
||||
enchanted.getToughness().setValue(toughness);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import mage.game.permanent.Permanent;
|
|||
|
||||
/**
|
||||
*
|
||||
* IMPORTANT: This only adds the chosen subtype while the source permanent is entering the battlefield.
|
||||
* You should also use @link{mage.abilities.effects.common.continuous.AddChosenSubtypeEffect} to make the subtype persist.
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class EnterAttributeAddChosenSubtypeEffect extends OneShotEffect {
|
||||
|
|
@ -34,12 +36,8 @@ public class EnterAttributeAddChosenSubtypeEffect extends OneShotEffect {
|
|||
Permanent permanent = game.getPermanentEntering(source.getSourceId());
|
||||
SubType subtype = (SubType) game.getState().getValue(source.getSourceId() + "_type");
|
||||
if (permanent != null && subtype != null) {
|
||||
MageObject mageObject = permanent.getBasicMageObject(game);
|
||||
if (!mageObject.getSubtype(null).contains(subtype)) {
|
||||
mageObject.getSubtype(null).add(subtype);
|
||||
}
|
||||
if (!permanent.getSubtype(null).contains(subtype)) {
|
||||
permanent.getSubtype(null).add(subtype);
|
||||
if (!permanent.getSubtype(game).contains(subtype)) {
|
||||
permanent.getSubtype(game).add(subtype);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Plopman
|
||||
*/
|
||||
public class CommanderStormAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public CommanderStormAbility() {
|
||||
super(Zone.STACK, new CommanderStormEffect());
|
||||
this.ruleAtTheTop = true;
|
||||
}
|
||||
|
||||
private CommanderStormAbility(final CommanderStormAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommanderStormAbility copy() {
|
||||
return new CommanderStormAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.SPELL_CAST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getSourceId().equals(getSourceId())) {
|
||||
StackObject spell = game.getStack().getStackObject(getSourceId());
|
||||
if (spell instanceof Spell) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setValue("StormSpell", spell);
|
||||
effect.setValue("StormSpellRef", new MageObjectReference(spell.getId(), game));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "When you cast this spell, copy it for each time you've "
|
||||
+ "cast your commander from the command zone this game. "
|
||||
+ "You may choose new targets for the copies.";
|
||||
}
|
||||
}
|
||||
|
||||
class CommanderStormEffect extends OneShotEffect {
|
||||
|
||||
public CommanderStormEffect() {
|
||||
super(Outcome.Copy);
|
||||
}
|
||||
|
||||
public CommanderStormEffect(final CommanderStormEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
MageObjectReference spellRef = (MageObjectReference) this.getValue("StormSpellRef");
|
||||
if (spellRef == null) {
|
||||
return false;
|
||||
}
|
||||
int stormCount = 0;
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
stormCount = player.getCommandersIds().stream().map(
|
||||
(commanderId) -> (Integer) game.getState().getValue(commanderId + "_castCount")
|
||||
).map((castCount) -> castCount).reduce(stormCount, Integer::sum);
|
||||
if (stormCount == 0) {
|
||||
return true;
|
||||
}
|
||||
Spell spell = (Spell) this.getValue("StormSpell");
|
||||
if (spell == null) {
|
||||
return false;
|
||||
}
|
||||
game.informPlayers(spell.getLogName() + " will be copied " + stormCount + " time" + (stormCount > 1 ? "s" : ""));
|
||||
for (int i = 0; i < stormCount; i++) {
|
||||
spell.createCopyOnStack(game, source, source.getControllerId(), true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommanderStormEffect copy() {
|
||||
return new CommanderStormEffect(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -779,7 +779,15 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
@Override
|
||||
public boolean addCounters(Counter counter, Ability source, Game game, List<UUID> appliedEffects, boolean isEffect) {
|
||||
boolean returnCode = true;
|
||||
UUID sourceId = (source == null ? getId() : source.getSourceId());
|
||||
UUID sourceId = getId();
|
||||
if (source != null) {
|
||||
MageObject object = game.getObject(source.getId());
|
||||
if (object instanceof StackObject) {
|
||||
sourceId = source.getId();
|
||||
} else {
|
||||
sourceId = source.getSourceId();
|
||||
}
|
||||
}
|
||||
GameEvent countersEvent = GameEvent.getEvent(GameEvent.EventType.ADD_COUNTERS, objectId, sourceId, getControllerOrOwner(), counter.getName(), counter.getCount());
|
||||
countersEvent.setAppliedEffects(appliedEffects);
|
||||
countersEvent.setFlag(isEffect);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
package mage.cards;
|
||||
|
||||
import mage.ObjectColor;
|
||||
import mage.cards.repository.CardCriteria;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
|
|
@ -96,7 +97,11 @@ public abstract class ExpansionSet implements Serializable {
|
|||
protected int numBoosterRare;
|
||||
protected int numBoosterDoubleFaced; // -1 = include normally 0 = exclude 1-n = include explicit
|
||||
protected int ratioBoosterMythic;
|
||||
protected boolean needsLegends = false;
|
||||
|
||||
protected boolean needsLegendCreature = false;
|
||||
protected boolean validateBoosterColors = true;
|
||||
protected double rejectMissingColorProbability = 0.8;
|
||||
protected double rejectSameColorUncommonsProbability = 0.8;
|
||||
|
||||
protected int maxCardNumberInBooster; // used to omit cards with collector numbers beyond the regular cards in a set for boosters
|
||||
|
||||
|
|
@ -186,17 +191,83 @@ public abstract class ExpansionSet implements Serializable {
|
|||
}
|
||||
|
||||
public List<Card> createBooster() {
|
||||
if (needsLegends) {
|
||||
for (int i = 0; i < 100000; i++) {//don't want to somehow loop forever
|
||||
List<Card> booster = tryBooster();
|
||||
for (Card card : booster) {
|
||||
if (card.isLegendary() && card.isCreature()) {// Dominaria packs must contain at least one legendary creature.
|
||||
return booster;
|
||||
for (int i = 0; i < 100; i++) {//don't want to somehow loop forever
|
||||
List<Card> booster = tryBooster();
|
||||
if (boosterIsValid(booster)) {
|
||||
return booster;
|
||||
}
|
||||
}
|
||||
return tryBooster();
|
||||
}
|
||||
|
||||
protected boolean boosterIsValid(List<Card> booster) {
|
||||
if (validateBoosterColors) {
|
||||
if (!validateColors(booster)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsLegendCreature) {
|
||||
if (booster.stream().noneMatch(card -> card.isLegendary() && card.isCreature())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean validateColors(List<Card> booster) {
|
||||
List<ObjectColor> magicColors =
|
||||
Arrays.asList(ObjectColor.WHITE, ObjectColor.BLUE, ObjectColor.BLACK, ObjectColor.RED, ObjectColor.GREEN);
|
||||
|
||||
// all cards colors
|
||||
Map<ObjectColor, Integer> colorWeight = new HashMap<>();
|
||||
// uncommon/rare/mythic cards colors
|
||||
Map<ObjectColor, Integer> uncommonWeight = new HashMap<>();
|
||||
|
||||
for (ObjectColor color : magicColors) {
|
||||
colorWeight.put(color, 0);
|
||||
uncommonWeight.put(color, 0);
|
||||
}
|
||||
|
||||
// count colors in the booster
|
||||
for (Card card : booster) {
|
||||
ObjectColor cardColor = card.getColor(null);
|
||||
if (cardColor != null) {
|
||||
List<ObjectColor> colors = cardColor.getColors();
|
||||
// todo: do we need gold color?
|
||||
colors.remove(ObjectColor.GOLD);
|
||||
if (!colors.isEmpty()) {
|
||||
// 60 - full card weight
|
||||
// multicolored cards add part of the weight to each color
|
||||
int cardColorWeight = 60 / colors.size();
|
||||
for (ObjectColor color : colors) {
|
||||
colorWeight.put(color, colorWeight.get(color) + cardColorWeight);
|
||||
if (card.getRarity() != Rarity.COMMON) {
|
||||
uncommonWeight.put(color, uncommonWeight.get(color) + cardColorWeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return tryBooster();
|
||||
|
||||
// check that all colors are present
|
||||
if (magicColors.stream().anyMatch(color -> colorWeight.get(color) < 60)) {
|
||||
// reject only part of the boosters
|
||||
if (RandomUtil.nextDouble() < rejectMissingColorProbability) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// check that we don't have 3 or more uncommons/rares of the same color
|
||||
if (magicColors.stream().anyMatch(color -> uncommonWeight.get(color) >= 180)) {
|
||||
// reject only part of the boosters
|
||||
if (RandomUtil.nextDouble() < rejectSameColorUncommonsProbability) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<Card> tryBooster() {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
package mage.constants;
|
||||
|
||||
import mage.util.SubTypeList;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import mage.util.SubTypeList;
|
||||
|
||||
public enum SubType {
|
||||
|
||||
//205.3k Instants and sorceries share their lists of subtypes; these subtypes are called spell types.
|
||||
|
|
@ -367,6 +367,7 @@ public enum SubType {
|
|||
ZUBERA("Zubera", SubTypeSet.CreatureType),
|
||||
// Planeswalker
|
||||
AJANI("Ajani", SubTypeSet.PlaneswalkerType),
|
||||
AMINATOU("Aminatou", SubTypeSet.PlaneswalkerType),
|
||||
ANGRATH("Angrath", SubTypeSet.PlaneswalkerType),
|
||||
ARLINN("Arlinn", SubTypeSet.PlaneswalkerType),
|
||||
ASHIOK("Ashiok", SubTypeSet.PlaneswalkerType),
|
||||
|
|
@ -379,6 +380,7 @@ public enum SubType {
|
|||
DOOKU("Dooku", SubTypeSet.PlaneswalkerType, true), // Star Wars
|
||||
DOVIN("Dovin", SubTypeSet.PlaneswalkerType),
|
||||
ELSPETH("Elspeth", SubTypeSet.PlaneswalkerType),
|
||||
ESTRID("Estrid", SubTypeSet.PlaneswalkerType),
|
||||
FREYALISE("Freyalise", SubTypeSet.PlaneswalkerType),
|
||||
GARRUK("Garruk", SubTypeSet.PlaneswalkerType),
|
||||
GIDEON("Gideon", SubTypeSet.PlaneswalkerType),
|
||||
|
|
@ -410,6 +412,7 @@ public enum SubType {
|
|||
VIVIEN("Vivien", SubTypeSet.PlaneswalkerType),
|
||||
VRASKA("Vraska", SubTypeSet.PlaneswalkerType),
|
||||
WILL("Will", SubTypeSet.PlaneswalkerType),
|
||||
WINDGRACE("Windgrace", SubTypeSet.PlaneswalkerType),
|
||||
XENAGOS("Xenagos", SubTypeSet.PlaneswalkerType),
|
||||
YANGGU("Yanggu", SubTypeSet.PlaneswalkerType),
|
||||
YANLING("Yanling", SubTypeSet.PlaneswalkerType),
|
||||
|
|
@ -460,8 +463,6 @@ public enum SubType {
|
|||
return null;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
public SubTypeSet getSubTypeSet() {
|
||||
return subTypeSet;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ public enum CounterType {
|
|||
SHIELD("shield"),
|
||||
SHRED("shred"),
|
||||
SLIME("slime"),
|
||||
SLUMBER("slumber"),
|
||||
SOOT("soot"),
|
||||
SPITE("spite"),
|
||||
SPORE("spore"),
|
||||
|
|
|
|||
|
|
@ -1,29 +1,26 @@
|
|||
|
||||
package mage.filter.predicate.mageobject;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.effects.common.ChooseCreatureTypeEffect;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.predicate.Predicate;
|
||||
import mage.filter.predicate.ObjectPlayerPredicate;
|
||||
import mage.filter.predicate.ObjectSourcePlayer;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LoneFox
|
||||
*/
|
||||
public class ChosenSubtypePredicate implements Predicate<MageObject> {
|
||||
public class ChosenSubtypePredicate implements ObjectPlayerPredicate<ObjectSourcePlayer<MageObject>> {
|
||||
|
||||
private final UUID cardID;
|
||||
|
||||
public ChosenSubtypePredicate(UUID cardID) {
|
||||
this.cardID = cardID;
|
||||
public ChosenSubtypePredicate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(MageObject input, Game game) {
|
||||
SubType subType = ChooseCreatureTypeEffect.getChoosenCreatureType(cardID, game);
|
||||
return input.hasSubtype(subType, game);
|
||||
public boolean apply(ObjectSourcePlayer<MageObject> input, Game game) {
|
||||
SubType subType = ChooseCreatureTypeEffect.getChoosenCreatureType(input.getSourceId(), game);
|
||||
return input.getObject().hasSubtype(subType, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
public final class BrudicladTelchorMyrToken extends TokenImpl {
|
||||
|
||||
final static private List<String> tokenImageSets = new ArrayList<>();
|
||||
|
||||
static {
|
||||
tokenImageSets.addAll(Arrays.asList("C18"));
|
||||
}
|
||||
|
||||
public BrudicladTelchorMyrToken() {
|
||||
this((String)null);
|
||||
}
|
||||
|
||||
public BrudicladTelchorMyrToken(String expansionSetCode) {
|
||||
super("Myr", "2/1 blue Myr artifact creature token");
|
||||
this.setOriginalExpansionSetCode(expansionSetCode);
|
||||
cardType.add(CardType.CREATURE);
|
||||
cardType.add(CardType.ARTIFACT);
|
||||
subtype.add(SubType.MYR);
|
||||
color.setBlue(true);
|
||||
power = new MageInt(2);
|
||||
toughness = new MageInt(1);
|
||||
|
||||
availableImageSetCodes = tokenImageSets;
|
||||
}
|
||||
|
||||
public BrudicladTelchorMyrToken(final BrudicladTelchorMyrToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public BrudicladTelchorMyrToken copy() {
|
||||
return new BrudicladTelchorMyrToken(this);
|
||||
}
|
||||
}
|
||||
43
Mage/src/main/java/mage/game/permanent/token/MaskToken.java
Normal file
43
Mage/src/main/java/mage/game/permanent/token/MaskToken.java
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.keyword.EnchantAbility;
|
||||
import mage.abilities.keyword.TotemArmorAbility;
|
||||
import mage.constants.Outcome;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class MaskToken extends TokenImpl {
|
||||
|
||||
public MaskToken() {
|
||||
super(
|
||||
"Mask", "white Aura enchantment token named Mask "
|
||||
+ "attached to another target permanent. "
|
||||
+ "The token has enchant permanent and totem armor."
|
||||
);
|
||||
cardType.add(CardType.ENCHANTMENT);
|
||||
color.setWhite(true);
|
||||
subtype.add(SubType.AURA);
|
||||
|
||||
TargetPermanent auraTarget = new TargetPermanent();
|
||||
Ability ability = new EnchantAbility(auraTarget.getTargetName());
|
||||
ability.addEffect(new AttachEffect(Outcome.BoostCreature));
|
||||
this.addAbility(ability);
|
||||
|
||||
this.addAbility(new TotemArmorAbility());
|
||||
}
|
||||
|
||||
public MaskToken(final MaskToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public MaskToken copy() {
|
||||
return new MaskToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.DiesTriggeredAbility;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
import mage.abilities.keyword.DefenderAbility;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class NestingDragonToken extends TokenImpl {
|
||||
|
||||
public NestingDragonToken() {
|
||||
super(
|
||||
"Dragon Egg",
|
||||
"0/2 red Dragon Egg creature token with defender and "
|
||||
+ "\""
|
||||
+ "When this creature dies, "
|
||||
+ "create a 2/2 red Dragon creature token with flying and "
|
||||
+ "'{R}: This creature gets +1/+0 until end of turn.'"
|
||||
+ "\""
|
||||
);
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setRed(true);
|
||||
subtype.add(SubType.DRAGON);
|
||||
subtype.add(SubType.EGG);
|
||||
power = new MageInt(0);
|
||||
toughness = new MageInt(2);
|
||||
addAbility(DefenderAbility.getInstance());
|
||||
this.addAbility(new DiesTriggeredAbility(
|
||||
new CreateTokenEffect(new DragonEggDragonToken()), false
|
||||
));
|
||||
}
|
||||
|
||||
public NestingDragonToken(final NestingDragonToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public NestingDragonToken copy() {
|
||||
return new NestingDragonToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -26,4 +26,8 @@ public final class RandomUtil {
|
|||
public static boolean nextBoolean() {
|
||||
return ThreadLocalRandom.current().nextBoolean();
|
||||
}
|
||||
|
||||
public static double nextDouble() {
|
||||
return ThreadLocalRandom.current().nextDouble();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue