Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DSK] Implement Omnivorous Flytrap #13083

Merged
merged 4 commits into from
Nov 30, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions Mage.Sets/src/mage/cards/o/OmnivorousFlytrap.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package mage.cards.o;

import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility;
import mage.abilities.condition.IntCompareCondition;
import mage.abilities.condition.common.DeliriumCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.DistributeCountersEffect;
import mage.abilities.hint.common.CardTypesInGraveyardHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanentAmount;

import java.util.UUID;

/**
* @author Cguy7777
*/
public final class OmnivorousFlytrap extends CardImpl {

public OmnivorousFlytrap(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}");

this.subtype.add(SubType.PLANT);
this.power = new MageInt(2);
this.toughness = new MageInt(4);

// Delirium -- Whenever Omnivorous Flytrap enters or attacks,
// if there are four or more card types among cards in your graveyard,
// distribute two +1/+1 counters among one or two target creatures.
// Then if there are six or more card types among cards in your graveyard,
// double the number of +1/+1 counters on those creatures.
Cguy7777 marked this conversation as resolved.
Show resolved Hide resolved
Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(
new DistributeCountersEffect(CounterType.P1P1, 2, "one or two target creatures"))
.withInterveningIf(DeliriumCondition.instance);
ability.addEffect(new ConditionalOneShotEffect(
new OmnivorousFlytrapEffect(),
new OmnivorousFlytrapCondition())
.concatBy("Then"));
TargetCreaturePermanentAmount target = new TargetCreaturePermanentAmount(2);
target.setMinNumberOfTargets(1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

curious - why is this necessary, was it bugged without it? compare e.g. Armament Corps

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before I added the line setting a minimum number of targets, the game allowed you to choose zero targets for the ability, which I don't believe is technically allowed?

I just tried [[Armament Corps]], and it lets you choose zero targets.

Looking through open issues, maybe this is what #9457 is about?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I had fixed a separate bug with #11341. I wasn't sure what 9457 was referring to, but this seems like a good guess.

As I understand it, with typical templating, max amounts of 2 or 3 are written as "one or two" or "one, two, or three" implying minimum 1, while higher numbers use "up to" or "any number" implying minimum 0. So I think in TargetAmount constructor, the minimum number of targets should be set using that logic, avoiding the need to specify per card.

Can confirm by then adjusting DamageMultiEffect and DistributeCountersEffect text gen to use description from target pointer rather than hardcoded target. Not sure if any other effect classes in scope? Or if there are any exceptions?

Maybe best as a separate PR.

scryfall search for potentially impacted cards

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll start working on a PR for this. For this card, I've switched it back to using the shorter and more typical target code, which will work properly (requiring at least one target) once that future PR is finished.

Copy link
Contributor

@xenohedron xenohedron Nov 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some exceptions: https://scryfall.com/search?q=o%3A%22among+up+to+t%22&unique=cards&as=grid&order=released

would you mind writing up an issue (either fresh or taking over 9457) to describe your intended scope? I'm thinking we might want a TargetAmount constructor that specifies, but open to various approaches. I have some unrelated cleanup to TargetAmount classes and DistributeCountersEffect constructors that I'll try to push soon (edit: pushed)

ability.addTarget(target);
ability.addHint(CardTypesInGraveyardHint.YOU);
this.addAbility(ability.setAbilityWord(AbilityWord.DELIRIUM));
}

private OmnivorousFlytrap(final OmnivorousFlytrap card) {
super(card);
}

@Override
public OmnivorousFlytrap copy() {
return new OmnivorousFlytrap(this);
}
}

class OmnivorousFlytrapEffect extends OneShotEffect {

OmnivorousFlytrapEffect() {
super(Outcome.Benefit);
staticText = "double the number of +1/+1 counters on those creatures";
}

private OmnivorousFlytrapEffect(final OmnivorousFlytrapEffect effect) {
super(effect);
}

@Override
public OmnivorousFlytrapEffect copy() {
return new OmnivorousFlytrapEffect(this);
}

@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}

for (UUID targetId : getTargetPointer().getTargets(game, source)) {
Permanent permanent = game.getPermanent(targetId);
if (permanent != null) {
int existingCounters = permanent.getCounters(game).getCount(CounterType.P1P1);
if (existingCounters > 0) {
permanent.addCounters(CounterType.P1P1.createInstance(existingCounters), source, game);
}
}
}
return true;
}
}

class OmnivorousFlytrapCondition extends IntCompareCondition {

OmnivorousFlytrapCondition() {
super(ComparisonType.OR_GREATER, 6);
}

@Override
protected int getInputValue(Game game, Ability source) {
return CardTypesInGraveyardCount.YOU.calculate(game, source, null);
}

@Override
public String toString() {
return "if there are six or more card types among cards in your graveyard";
}
}
2 changes: 2 additions & 0 deletions Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ private DuskmournHouseOfHorror() {
cards.add(new SetCardInfo("Niko, Light of Hope", 224, Rarity.MYTHIC, mage.cards.n.NikoLightOfHope.class));
cards.add(new SetCardInfo("Norin, Swift Survivalist", 145, Rarity.UNCOMMON, mage.cards.n.NorinSwiftSurvivalist.class));
cards.add(new SetCardInfo("Oblivious Bookworm", 225, Rarity.UNCOMMON, mage.cards.o.ObliviousBookworm.class));
cards.add(new SetCardInfo("Omnivorous Flytrap", 192, Rarity.RARE, mage.cards.o.OmnivorousFlytrap.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Omnivorous Flytrap", 322, Rarity.RARE, mage.cards.o.OmnivorousFlytrap.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Optimistic Scavenger", 21, Rarity.UNCOMMON, mage.cards.o.OptimisticScavenger.class));
cards.add(new SetCardInfo("Orphans of the Wheat", 22, Rarity.UNCOMMON, mage.cards.o.OrphansOfTheWheat.class));
cards.add(new SetCardInfo("Overlord of the Balemurk", 113, Rarity.MYTHIC, mage.cards.o.OverlordOfTheBalemurk.class));
Expand Down