Help implementing a card
Moderators: BetaSteward, noxx, jeffwadsworth, JayDi, TheElk801, LevelX, North, CCGHQ Admins
Re: Help implementing a card
by fireshoes » 21 Jul 2015, 12:21
Any hints as to why BoostOpponentsEffect isn't doing anything when Sickness wins the vote on Bite of the Black Rose?
- Code: Select all
public class BiteOfTheBlackRose extends CardImpl {
public BiteOfTheBlackRose(UUID ownerId) {
super(ownerId, 26, "Bite of the Black Rose", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{3}{B}");
this.expansionSetCode = "CNS";
// Will of the council - Starting with you, each player votes for sickness or psychosis. If sickness gets more votes, creatures your opponents control get -2/-2 until end of turn. If psychosis gets more votes or the vote is tied, each opponent discards two cards.
this.getSpellAbility().addEffect(new BiteOfTheBlackRoseEffect());
}
public BiteOfTheBlackRose(final BiteOfTheBlackRose card) {
super(card);
}
@Override
public BiteOfTheBlackRose copy() {
return new BiteOfTheBlackRose(this);
}
}
class BiteOfTheBlackRoseEffect extends OneShotEffect {
BiteOfTheBlackRoseEffect() {
super(Outcome.Benefit);
this.staticText = "<i>Will of the council</i> - Starting with you, each player votes for sickness or psychosis. If sickness gets more votes, creatures your opponents control get -2/-2 until end of turn. If psychosis gets more votes or the vote is tied, each opponent discards two cards";
}
BiteOfTheBlackRoseEffect(final BiteOfTheBlackRoseEffect effect) {
super(effect);
}
@Override
public BiteOfTheBlackRoseEffect copy() {
return new BiteOfTheBlackRoseEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
int sicknessCount = 0;
int psychosisCount = 0;
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId);
if (player != null) {
if (player.chooseUse(Outcome.ExtraTurn, "Choose sickness?", source, game)) {
sicknessCount++;
game.informPlayers(player.getLogName() + " has chosen: sickness");
} else {
psychosisCount++;
game.informPlayers(player.getLogName() + " has chosen: psychosis");
}
}
}
if (sicknessCount > psychosisCount) {
new BoostOpponentsEffect(-2, -2, Duration.EndOfTurn).apply(game, source);
} else {
new DiscardEachPlayerEffect(new StaticValue(2), false, TargetController.OPPONENT).apply(game, source);
}
return true;
}
return false;
}
}
Re: Help implementing a card
by LevelX » 21 Jul 2015, 12:46
You need to add the continuous effect to the game.
It's no one shot effect that you can simply apply once.
It's no one shot effect that you can simply apply once.
-

LevelX - DEVELOPER
- Posts: 1677
- Joined: 08 Dec 2011, 15:08
- Has thanked: 174 times
- Been thanked: 374 times
Re: Help implementing a card
by fireshoes » 21 Jul 2015, 16:06
Sent you a PM about some cards yesterday too, in case you didn't get a notification. 
Re: Help implementing a card
by EvilGeek » 21 Jul 2015, 17:27
I'm having trouble with the card Override. Its name is conflicting with the @Override annotation and my IDE doesn't like it (I use Eclipse btw). Just wondering if anyone has a fix, is it possible to have the class name different to the card name but still have it work normally?
- EvilGeek
- Posts: 8
- Joined: 27 Nov 2014, 16:56
- Has thanked: 0 time
- Been thanked: 0 time
Re: Help implementing a card
by LoneFox » 28 Jul 2015, 19:58
- Code: Select all
public class ScorchingLava extends CardImpl {
public ScorchingLava(UUID ownerId) {
super(ownerId, 164, "Scorching Lava", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{R}");
this.expansionSetCode = "INV";
// Kicker {R}
this.addAbility(new KickerAbility("{R}"));
// Scorching Lava deals 2 damage to target creature or player. If Scorching Lava was kicked, that creature can't be regenerated this turn and if it would die this turn, exile it instead.
this.getSpellAbility().addEffect(new DamageTargetEffect(2));
this.getSpellAbility().addEffect(new ConditionalContinuousRuleModifyingEffect(
new CantRegenerateTargetEffect(Duration.EndOfTurn, "That creature"), KickedCondition.getInstance()));
Effect effect = new ConditionalReplacementEffect(new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn),
KickedCondition.getInstance());
effect.setText("and if it would die this turn, exile it instead");
this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetCreatureOrPlayer());
this.getSpellAbility().addWatcher(new DamagedByWatcher());
}
public ScorchingLava(final ScorchingLava card) {
super(card);
}
@Override
public ScorchingLava copy() {
return new ScorchingLava(this);
}
}
Re: Help implementing a card
by LevelX » 28 Jul 2015, 20:50
Look e.g. to Savage Offensive to see how to do it.
- Code: Select all
// If Savage Offensive was kicked, they get +1/+1 until end of turn.
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(
new AddContinuousEffectToGame(new BoostControlledEffect(1, 1, Duration.EndOfTurn)),
KickedCondition.getInstance(),
"If {this} was kicked, they get +1/+1 until end of turn."));
-

LevelX - DEVELOPER
- Posts: 1677
- Joined: 08 Dec 2011, 15:08
- Has thanked: 174 times
- Been thanked: 374 times
Re: Help implementing a card
by LoneFox » 29 Jul 2015, 07:35
Turns out I was using a buggy card (Explosive Growth) as reference...
The simplest solution appears to be:
The simplest solution appears to be:
- Code: Select all
new LockedInCondition(KickedCondition.getInstance())
Re: Help implementing a card
by fireshoes » 29 Jul 2015, 18:05
Feel like I'm missing something simple here. The exiled cards don't return when the second ability is used. It's same effect as Helvault, except Helvault is triggered while this activated.
- Code: Select all
// {3}: Exile target creature you control.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new GenericManaCost(3));
ability.addTarget(new TargetControlledCreaturePermanent());
this.addAbility(ability);
// Sacrifice Cold Storage: Return each creature card exiled with Cold Storage to the battlefield under your control.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), new SacrificeSourceCost()));
Re: Help implementing a card
by LevelX » 29 Jul 2015, 18:33
I prefer the Savage Offensive solution because there is no conditional effect overhead for the duration of the continuous effect.LoneFox wrote:Turns out I was using a buggy card (Explosive Growth) as reference...
The simplest solution appears to be:
- Code: Select all
new LockedInCondition(KickedCondition.getInstance())
-

LevelX - DEVELOPER
- Posts: 1677
- Joined: 08 Dec 2011, 15:08
- Has thanked: 174 times
- Been thanked: 374 times
Re: Help implementing a card
by LoneFox » 03 Aug 2015, 08:25
Dralnu's Pet. I did find the DiscardCardCost under a large pile of object-oriented spaghetti, but why is the discarded card not stored in the cost? Trying to access it throws IndexOutOfBoundsException.
- Code: Select all
public class DralnusPet extends CardImpl {
public DralnusPet(UUID ownerId) {
super(ownerId, 23, "Dralnu's Pet", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{U}{U}");
this.expansionSetCode = "PLS";
this.subtype.add("Shapeshifter");
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Kicker-{2}{B}, Discard a creature card.
Costs<Cost> kickerCosts = new CostsImpl<>();
kickerCosts.add(new ManaCostsImpl<>("{2}{B}"));
kickerCosts.add(new DiscardCardCost(new FilterCreatureCard()));
this.addAbility(new KickerAbility(kickerCosts));
// If Dralnu's Pet was kicked, it enters the battlefield with flying and with X +1/+1 counters on it, where X is the discarded card's converted mana cost.
Ability ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(),
new DralnusPetDiscardCMC(), true), KickedCondition.getInstance(), true,
"If {this} was kicked, it enters the battlefield with flying and with X +1/+1 counters on it, where X is the discarded card's converted mana cost", "");
ability.addEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield));
this.addAbility(ability);
}
public DralnusPet(final DralnusPet card) {
super(card);
}
@Override
public DralnusPet copy() {
return new DralnusPet(this);
}
}
class DralnusPetDiscardCMC implements DynamicValue {
public DralnusPetDiscardCMC() {
}
@Override
public int calculate(Game game, Ability source, Effect effect) {
int count = 0;
Card card = game.getCard(source.getSourceId());
if(card != null) {
for(Ability ability: card.getAbilities()) {
if(ability instanceof KickerAbility) {
for(OptionalAdditionalCost cost1: ((KickerAbility)ability).getKickerCosts()) {
for(Object cost2: (OptionalAdditionalCostImpl)cost1) {
for(Object cost3: (CostsImpl)cost2) {
if(cost3 instanceof DiscardCardCost) {
return ((DiscardCardCost)cost3).getCards().get(0).getManaCost().convertedManaCost();
}
}
}
}
}
}
}
return 0;
}
@Override
public DralnusPetDiscardCMC copy() {
return new DralnusPetDiscardCMC();
}
@Override
public String getMessage() {
return "the discarded card's converted mana cost";
}
}
Re: Help implementing a card
by LevelX » 03 Aug 2015, 12:01
Problem here is that the payed kicker cost is payed with the spell ability and is only saved there.LoneFox wrote:Dralnu's Pet. I did find the DiscardCardCost under a large pile of object-oriented spaghetti, but why is the discarded card not stored in the cost? Trying to access it throws IndexOutOfBoundsException.
So you have to do it the way it's done for cards like Protean Hydra and get the spell ability.
Here's the code that works:
- Code: Select all
public class DralnusPet extends CardImpl {
public DralnusPet(UUID ownerId) {
super(ownerId, 23, "Dralnu's Pet", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{U}{U}");
this.expansionSetCode = "PLS";
this.subtype.add("Shapeshifter");
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Kicker-{2}{B}, Discard a creature card.
Costs<Cost> kickerCosts = new CostsImpl<>();
kickerCosts.add(new ManaCostsImpl<>("{2}{B}"));
kickerCosts.add(new DiscardCardCost(new FilterCreatureCard()));
this.addAbility(new KickerAbility(kickerCosts));
// If Dralnu's Pet was kicked, it enters the battlefield with flying and with X +1/+1 counters on it, where X is the discarded card's converted mana cost.
Ability ability = new EntersBattlefieldAbility(new DralnusPetEffect(), KickedCondition.getInstance(), true,
"If {this} was kicked, it enters the battlefield with flying and with X +1/+1 counters on it, where X is the discarded card's converted mana cost", "");
ability.addEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield));
this.addAbility(ability);
}
public DralnusPet(final DralnusPet card) {
super(card);
}
@Override
public DralnusPet copy() {
return new DralnusPet(this);
}
}
class DralnusPetEffect extends OneShotEffect {
public DralnusPetEffect() {
super(Outcome.BoostCreature);
this.staticText = "and with X +1/+1 counters on it, where X is the discarded card's converted mana cost";
}
public DralnusPetEffect(final DralnusPetEffect effect) {
super(effect);
}
@Override
public DralnusPetEffect copy() {
return new DralnusPetEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getSourceId());
if (controller != null && permanent != null) {
Object obj = getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY);
if (obj != null && obj instanceof SpellAbility) {
int cmc = 0;
for (Cost cost : ((SpellAbility) obj).getCosts()) {
if (cost instanceof DiscardCardCost && ((DiscardCardCost) cost).getCards().size() > 0) {
cmc = ((DiscardCardCost) cost).getCards().get(0).getManaCost().convertedManaCost();
}
if (cmc > 0) {
return new AddCountersSourceEffect(CounterType.P1P1.createInstance(cmc), true).apply(game, source);
}
}
}
return true;
}
return false;
}
}
-

LevelX - DEVELOPER
- Posts: 1677
- Joined: 08 Dec 2011, 15:08
- Has thanked: 174 times
- Been thanked: 374 times
Re: Help implementing a card
by LoneFox » 03 Aug 2015, 13:16
Thanks! I pushed it and a few other new cards to my repository.LevelX wrote:Problem here is that the payed kicker cost is payed with the spell ability and is only saved there.
So you have to do it the way it's done for cards like Protean Hydra and get the spell ability.
Here's the code that works:
Re: Help implementing a card
by fireshoes » 03 Aug 2015, 18:35
Got any hints for this one?fireshoes wrote:Feel like I'm missing something simple here. The exiled cards don't return when the second ability is used. It's same effect as Helvault, except Helvault is triggered while this activated.
- Code: Select all
// {3}: Exile target creature you control.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new GenericManaCost(3));
ability.addTarget(new TargetControlledCreaturePermanent());
this.addAbility(ability);
// Sacrifice Cold Storage: Return each creature card exiled with Cold Storage to the battlefield under your control.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), new SacrificeSourceCost()));
Re: Help implementing a card
by LevelX » 03 Aug 2015, 20:52
I guess you can set previousZone to true for ReturnFromExileForSourceEffect. Because you sacrifice the Storage to activate the ability the zone change counter is already raised during resolution.fireshoes wrote:Got any hints for this one?fireshoes wrote:Feel like I'm missing something simple here. The exiled cards don't return when the second ability is used. It's same effect as Helvault, except Helvault is triggered while this activated.
- Code: Select all
// {3}: Exile target creature you control.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new GenericManaCost(3));
ability.addTarget(new TargetControlledCreaturePermanent());
this.addAbility(ability);
// Sacrifice Cold Storage: Return each creature card exiled with Cold Storage to the battlefield under your control.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), new SacrificeSourceCost()));
But I'm sure there are still counter cases where the return effect won't work.
E.g. the Storage was removed from graveyard meanwhile.
I guess it's better to use ReturnFromExileEffect with a fixed exileId related to the zoneChangeCounter of the activatedAbilities.
-

LevelX - DEVELOPER
- Posts: 1677
- Joined: 08 Dec 2011, 15:08
- Has thanked: 174 times
- Been thanked: 374 times
Re: Help implementing a card
by EvilGeek » 04 Aug 2015, 16:17
Still stuck on this.EvilGeek wrote:I'm having trouble with the card Override. Its name is conflicting with the @Override annotation and my IDE doesn't like it (I use Eclipse btw). Just wondering if anyone has a fix, is it possible to have the class name different to the card name but still have it work normally?
- EvilGeek
- Posts: 8
- Joined: 27 Nov 2014, 16:56
- Has thanked: 0 time
- Been thanked: 0 time
Who is online
Users browsing this forum: No registered users and 0 guests