forked from External/mage
Implement offspring mechanic (#12572)
* implement offspring mechanic * create offspring test
This commit is contained in:
parent
6232368162
commit
204f67c5f0
3 changed files with 185 additions and 11 deletions
|
|
@ -4,15 +4,11 @@ import mage.cards.ExpansionSet;
|
|||
import mage.constants.Rarity;
|
||||
import mage.constants.SetType;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class Bloomburrow extends ExpansionSet {
|
||||
|
||||
private static final List<String> unfinished = Arrays.asList("Coruscation Mage", "Darkstar Augur", "Finch Formation", "Flowerfoot Swordmaster", "Iridescent Vinelasher", "Manifold Mouse", "Splash Lasher", "Steampath Charger", "Tender Wildguide", "Thundertrap Trainer", "Warren Warleader");
|
||||
private static final Bloomburrow instance = new Bloomburrow();
|
||||
|
||||
public static Bloomburrow getInstance() {
|
||||
|
|
@ -120,7 +116,5 @@ public final class Bloomburrow extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Wandertale Mentor", 240, Rarity.UNCOMMON, mage.cards.w.WandertaleMentor.class));
|
||||
cards.add(new SetCardInfo("Warren Warleader", 38, Rarity.MYTHIC, mage.cards.w.WarrenWarleader.class));
|
||||
cards.add(new SetCardInfo("Zoraline, Cosmos Caller", 242, Rarity.RARE, mage.cards.z.ZoralineCosmosCaller.class));
|
||||
|
||||
cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); // remove when mechanic is implemented
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
package org.mage.test.cards.abilities.keywords;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class OffspringTest extends CardTestPlayerBase {
|
||||
|
||||
private static final String vinelasher = "Iridescent Vinelasher";
|
||||
|
||||
private Permanent getCreature(String name, boolean isToken) {
|
||||
for (Permanent permanent : currentGame.getBattlefield().getActivePermanents(playerA.getId(), currentGame)) {
|
||||
if (name.equals(permanent.getName()) && (permanent instanceof PermanentToken) == isToken) {
|
||||
return permanent;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void checkOffspring(String name, int power, int toughness, boolean paid) {
|
||||
assertPermanentCount(playerA, name, paid ? 2 : 1);
|
||||
assertTokenCount(playerA, name, paid ? 1 : 0);
|
||||
|
||||
Permanent original = getCreature(name, false);
|
||||
Assert.assertEquals(
|
||||
"Original creature should have power " + power,
|
||||
power, original.getPower().getValue()
|
||||
);
|
||||
Assert.assertEquals(
|
||||
"Original creature should have toughness " + toughness,
|
||||
toughness, original.getToughness().getValue()
|
||||
);
|
||||
if (!paid) {
|
||||
return;
|
||||
}
|
||||
Permanent token = getCreature(name, true);
|
||||
Assert.assertEquals(
|
||||
"Token creature should have power 1",
|
||||
1, token.getPower().getValue()
|
||||
);
|
||||
Assert.assertEquals(
|
||||
"Token creature should have toughness 1",
|
||||
1, token.getToughness().getValue()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoPay() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
addCard(Zone.HAND, playerA, vinelasher);
|
||||
|
||||
setChoice(playerA, false);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, vinelasher);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
checkOffspring(vinelasher, 1, 2, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPay() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
addCard(Zone.HAND, playerA, vinelasher);
|
||||
|
||||
setChoice(playerA, true);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, vinelasher);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
checkOffspring(vinelasher, 1, 2, true);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +1,58 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.costs.*;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
* TODO: Implement this
|
||||
*/
|
||||
public class OffspringAbility extends StaticAbility {
|
||||
public class OffspringAbility extends StaticAbility implements OptionalAdditionalSourceCosts {
|
||||
|
||||
private static final String keywordText = "Offspring";
|
||||
private static final String reminderText = "You may pay an additional %s as you cast this spell. If you do, when this creature enters, create a 1/1 token copy of it.";
|
||||
private final String rule;
|
||||
|
||||
public static final String OFFSPRING_ACTIVATION_VALUE_KEY = "offspringActivation";
|
||||
|
||||
protected OptionalAdditionalCost additionalCost;
|
||||
|
||||
public OffspringAbility(String manaString) {
|
||||
this(new ManaCostsImpl<>(manaString));
|
||||
}
|
||||
|
||||
public OffspringAbility(Cost cost) {
|
||||
super(Zone.ALL, null);
|
||||
super(Zone.STACK, null);
|
||||
this.additionalCost = new OptionalAdditionalCostImpl(
|
||||
keywordText + ' ' + cost.getText(),
|
||||
String.format(reminderText, cost.getText()), cost
|
||||
);
|
||||
this.additionalCost.setRepeatable(false);
|
||||
this.rule = additionalCost.getName() + ' ' + additionalCost.getReminderText();
|
||||
this.setRuleAtTheTop(true);
|
||||
this.addSubAbility(new ConditionalInterveningIfTriggeredAbility(
|
||||
new EntersBattlefieldTriggeredAbility(new OffspringEffect()), OffspringCondition.instance,
|
||||
"When this creature enters, if its offspring cost was paid, create a 1/1 token copy of it."
|
||||
).setRuleVisible(false));
|
||||
}
|
||||
|
||||
private OffspringAbility(final OffspringAbility ability) {
|
||||
super(ability);
|
||||
this.rule = ability.rule;
|
||||
this.additionalCost = ability.additionalCost.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -28,8 +60,73 @@ public class OffspringAbility extends StaticAbility {
|
|||
return new OffspringAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOptionalAdditionalCosts(Ability ability, Game game) {
|
||||
if (!(ability instanceof SpellAbility)) {
|
||||
return;
|
||||
}
|
||||
Player player = game.getPlayer(ability.getControllerId());
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
additionalCost.reset();
|
||||
if (!additionalCost.canPay(ability, this, ability.getControllerId(), game)
|
||||
|| !player.chooseUse(Outcome.PutCreatureInPlay, "Pay " + additionalCost.getText(true) + " for offspring?", ability, game)) {
|
||||
return;
|
||||
}
|
||||
additionalCost.activate();
|
||||
for (Cost cost : ((Costs<Cost>) additionalCost)) {
|
||||
ability.getCosts().add(cost.copy());
|
||||
}
|
||||
ability.setCostsTag(OFFSPRING_ACTIVATION_VALUE_KEY, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCastMessageSuffix() {
|
||||
return additionalCost.getCastSuffixMessage(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Offspring";
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
|
||||
class OffspringEffect extends OneShotEffect {
|
||||
|
||||
OffspringEffect() {
|
||||
super(Outcome.Benefit);
|
||||
}
|
||||
|
||||
private OffspringEffect(final OffspringEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OffspringEffect copy() {
|
||||
return new OffspringEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = source.getSourcePermanentOrLKI(game);
|
||||
return permanent != null && new CreateTokenCopyTargetEffect(
|
||||
null, null, false, 1, false,
|
||||
false, null, 1, 1, false
|
||||
).setSavedPermanent(permanent).apply(game, source);
|
||||
}
|
||||
}
|
||||
|
||||
enum OffspringCondition implements Condition {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return CardUtil.checkSourceCostsTagExists(game, source, OffspringAbility.OFFSPRING_ACTIVATION_VALUE_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Offspring cost was paid";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue