It is currently 28 Apr 2024, 13:53
   
Text Size

Help implementing a card

Moderators: North, BetaSteward, noxx, jeffwadsworth, JayDi, TheElk801, LevelX, CCGHQ Admins

Re: Help implementing a card

Postby escplan9 » 29 Feb 2016, 13:39

Hello, I work as a developer and wanted to contribute to XMage. I decided I try to implement a card I use in my Rakdos, Lord of Riots EDH deck, Dread Cacodemon. I looked at cards programmed in XMage with similar effects, like Plague Wind for destroying all creatures you don't control, and Timbermare for tapping all other creatures. However, I'm not sure how to combine all of these to get the correct effect from the card.

This is what I have so far:
Code: Select all
    private static final FilterCreaturePermanent filterCreaturesDontControl = new FilterCreaturePermanent("creatures you don't control");
    static {
        filterCreaturesDontControl.add(new ControllerPredicate(TargetController.NOT_YOU));
    }
   
    // perhaps way to filter for all other creatures you control?
    private static final FilterCreaturePermanent filterOtherCreaturesYouControl = new FilterCreaturePermanent("other creatures you control");
    static {
        filterOtherCreaturesYouControl.add(new ControllerPredicate(TargetController.YOU));
        // add predicate for Creature != Dread Cacodemon?
    }

    public DreadCacodemon(UUID ownerId) {
        super(ownerId, 79, "Dread Cacodemon", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{7}{B}{B}{B}");
        this.expansionSetCode = "CMD";
        this.subtype.add("Demon");
        this.power = new MageInt(8);
        this.toughness = new MageInt(8);
       
        // When Dread Cacodemon enters the battlefield,
        // if you cast it from your hand, destroy all creatures your opponents control,
        // then tap all other creatures you control.
        Ability ability = new EntersBattlefieldTriggeredAbility(
                new ConditionalOneShotEffect(new DestroyAllEffect(filterCreaturesDontControl, false), new CastFromHandCondition(),
                " if you cast it from your hand, destroy all creatures your opponents control, then tap all other creatures you control."));
        this.addAbility(ability, new CastFromHandWatcher());
               
        /**
         * perhaps? Once I get the filter right.
        this.addAbility(new EntersBattlefieldTriggeredAbility(new TapAllEffect(filterOtherCreaturesYouControl)));   
         */   
    }
So the two things I need to finish the card is understanding:

1) How to make the filter for "other creatures you control" - other than Dread Cacodemon.
2) How to add the TapAllEffect into the EntersBattlefieldTriggeredAbility function afterwords. Should I just add another ability variable with a new EBTA object for the tap all portion? I'm not sure what would happen with two EBTA functions on the same card? Perhaps that is the correct way to do it since the card reads "destroy all creatures your opponents control, then tap all other creatures you control." Then again, I need all those effects to be dependent on the card being cast from the hand.

Any help would be appreciated here. Thanks.
Last edited by escplan9 on 29 Feb 2016, 15:48, edited 1 time in total.
escplan9
 
Posts: 257
Joined: 10 Aug 2015, 22:38
Has thanked: 26 times
Been thanked: 40 times

Re: Help implementing a card

Postby LevelX » 29 Feb 2016, 14:29

escplan9 wrote:1) How to make the filter for "other creatures you control" - other than Dread Cacodemon.
2) How to add the TapAllEffect into the EntersBattlefieldTriggeredAbility function afterwords. Should
Try it this way:
Code: Select all
    private static final FilterCreaturePermanent opponentsCreatures = new FilterCreaturePermanent("creatures your opponents control");
    static {
        opponentsCreatures.add(new ControllerPredicate(TargetController.OPPONENT));
    }
   
    private static final FilterCreaturePermanent filterOtherCreaturesYouControl = new FilterCreaturePermanent("other creatures you control");
    static {
        filterOtherCreaturesYouControl.add(new ControllerPredicate(TargetController.YOU));
        filterOtherCreaturesYouControl.add(new AnotherPredicate());
    }
...

        TriggeredAbility triggeredAbility = new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(opponentsCreatures, false));
        Effect effect = new TapAllEffect(filterOtherCreaturesYouControl);
        effect.setText("then tap all other creatures you control");
        triggeredAbility.addEffect(effect);
        this.addAbility(new ConditionalTriggeredAbility(triggeredAbility, new CastFromHandCondition(),
                "When {this} enters the battlefield, if you cast it from your hand, destroy all creatures your opponents control, then tap all other creatures you control."));
     

The ability / effect stacking needs some practice. That's normal. :-)
User avatar
LevelX
DEVELOPER
 
Posts: 1677
Joined: 08 Dec 2011, 15:08
Has thanked: 174 times
Been thanked: 374 times

Re: Help implementing a card

Postby escplan9 » 29 Feb 2016, 15:46

Thanks for the help! I think the card is nearly done (if not already). Now I want to test the card to be sure but I'm not seeing it within the Deck Editor.

I've followed the instructions to start the server in test mode, I have a test.dck and cheat.dck in Mage.Client directory. I also have init.txt in the Mage.Server/config directory. So from NetBeans I ran the Mage Server in test mode, then I run the Client and check the "Force Database Update" and connect to local host. When it tries to load the test.dck where I have the recently added card Dread Cacodemon:

1 [CMD:79] Dread Cacodemon

I see this error in the Client log: "FATAL 2016-02-29 10:39:00,159 Could not find card '' at line 82: 1 [CMD:79] Dread Cacodemon =>[AWT-EventQueue-0] DeckImporter.importDeck "

And when I open the Deck Editor and search for the card, it does not show up either. Am I missing a step for this card to be available in the database? And is my line in test.dck correct for the card?
escplan9
 
Posts: 257
Joined: 10 Aug 2015, 22:38
Has thanked: 26 times
Been thanked: 40 times

Re: Help implementing a card

Postby LevelX » 29 Feb 2016, 16:11

escplan9 wrote:Thanks for the help! I think the card is nearly done (if not already). Now I want to test the card to be sure but I'm not seeing it within the Deck Editor.

I've followed the instructions to start the server in test mode, I have a test.dck and cheat.dck in Mage.Client directory. I also have init.txt in the Mage.Server/config directory. So from NetBeans I ran the Mage Server in test mode, then I run the Client and check the "Force Database Update" and connect to local host. When it tries to load the test.dck where I have the recently added card Dread Cacodemon:

1 [CMD:79] Dread Cacodemon

I see this error in the Client log: "FATAL 2016-02-29 10:39:00,159 Could not find card '' at line 82: 1 [CMD:79] Dread Cacodemon =>[AWT-EventQueue-0] DeckImporter.importDeck "

And when I open the Deck Editor and search for the card, it does not show up either. Am I missing a step for this card to be available in the database? And is my line in test.dck correct for the card?
The server and the client has a DB that hold all cards.
As the server starts, it checks if there are new cards added to the classes and adds the new cards to the server db.

To get it to the client db you have to check on the option "force DB update" in the connection dialog. We've done it this way to prevent a complete DB check up on everyy connect to the server. Because in the majority of connect actions there is no need for a DB checkup and update.
User avatar
LevelX
DEVELOPER
 
Posts: 1677
Joined: 08 Dec 2011, 15:08
Has thanked: 174 times
Been thanked: 374 times

Re: Help implementing a card

Postby escplan9 » 29 Feb 2016, 18:14

In testing Dread Cacodemon with the adjustments Level X mentioned, nothing happens when it enters the battlefield. When I go back to simplifying the code, I can get it to do the "destroy all creatures you don't control" fine:

Code: Select all
        Ability ability = new EntersBattlefieldTriggeredAbility(
                new ConditionalOneShotEffect(new DestroyAllEffect(opponentsCreatures, false), new CastFromHandCondition(),
                " if you cast it from your hand, destroy all creatures your opponents control, then tap all other creatures you control."));
        this.addAbility(ability, new CastFromHandWatcher());
However I have not found a way to add on the TapAllEffect to it. What it was when I added in Level X's changes:

Code: Select all
    private static final FilterCreaturePermanent opponentsCreatures = new FilterCreaturePermanent("creatures your opponents control");
    static {
        opponentsCreatures.add(new ControllerPredicate(TargetController.OPPONENT));
    }
   
    private static final FilterCreaturePermanent otherCreaturesYouControl = new FilterCreaturePermanent("other creatures you control");
    static {
        otherCreaturesYouControl.add(new ControllerPredicate(TargetController.YOU));
        otherCreaturesYouControl.add(new AnotherPredicate());
    }

    public DreadCacodemon(UUID ownerId) {
        super(ownerId, 79, "Dread Cacodemon", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{7}{B}{B}{B}");
        this.expansionSetCode = "CMD";
        this.subtype.add("Demon");
        this.power = new MageInt(8);
        this.toughness = new MageInt(8);
       
        // When Dread Cacodemon enters the battlefield,
        // if you cast it from your hand, destroy all creatures your opponents control,
        // then tap all other creatures you control.       
        TriggeredAbility triggeredAbility = new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(opponentsCreatures, false));
        Effect effect = new TapAllEffect(otherCreaturesYouControl);
        effect.setText("then tap all other creatures you control");
        triggeredAbility.addEffect(effect);
        this.addAbility(new ConditionalTriggeredAbility(triggeredAbility, new CastFromHandCondition(),
                "When {this} enters the battlefield, if you cast it from your hand, destroy all creatures your opponents control, then tap all other creatures you control."));
    }
I don't see anything in the server or client log to further debug why it simply enters the battlefield and nothing happens with the code above. I've been trying to find ways to combine the working code mentioned earlier for destroying all the opponent's creatures, but then also adding the TapAllEffect to the ability and I haven't found a way to get that working yet.

edit: Nevermind, found a way to mix the two. Now I have opponent's creatures dying and my other ones tapped as expected. What I did:

Code: Select all
        Ability ability = new EntersBattlefieldTriggeredAbility(
                new ConditionalOneShotEffect(new DestroyAllEffect(opponentsCreatures, false), new CastFromHandCondition(),
                " if you cast it from your hand, destroy all creatures your opponents control, then tap all other creatures you control."));
        Effect effect = new TapAllEffect(otherCreaturesYouControl);
        ability.addEffect(effect);
        this.addAbility(ability, new CastFromHandWatcher());
edit2: Now the only remaining issue is the "when cast from hand" conditional. The "when cast from hand" conditional is preventing the opponent's creatures from being destroyed when I say re-animate the creature, as expected since I did not cast it from hand. However, it still is tapping my other creatures - which it shouldn't since it was not cast from hand. I need to make the TapAllEffect part of that same ConditionalEffect that is destroying the opponents creatures.
escplan9
 
Posts: 257
Joined: 10 Aug 2015, 22:38
Has thanked: 26 times
Been thanked: 40 times

Re: Help implementing a card

Postby escplan9 » 29 Feb 2016, 18:29

Damn... just when I thought "ah hah! looks good!" I had to go test the "when cast from hand" part and :(

What I currently have, where the only remaining issue is my other creatures are still being tapped when I do not cast this card from my hand (i.e. I reanimate it):

Code: Select all
        Ability ability = new EntersBattlefieldTriggeredAbility(
                new ConditionalOneShotEffect(new DestroyAllEffect(opponentsCreatures, false), new CastFromHandCondition(),
                " if you cast it from your hand, destroy all creatures your opponents control, then tap all other creatures you control."));
        Effect effect = new TapAllEffect(otherCreaturesYouControl);
        ability.addEffect(effect);
        this.addAbility(ability, new CastFromHandWatcher());
Any suggestions how to make the TapAllEffect part of the same "When cast from hand" conditional here? I could create new constructors to ConditionalOneShotEffect perhaps to allow it to perform two effects conditionally? Is there a better way?

edit: Looks like the ConditionalOneShotEffect already has a constructor taking 2 Effect variables, though it does something different than what I would want here:
public ConditionalOneShotEffect(OneShotEffect effect, OneShotEffect otherwiseEffect, Condition condition, String text)

I want both effects to be the same when the condition is true or false, not what this would do.

edit2: Actually, not sure the rules handing for the "then" clause on the card. Would there ever be a case where Dread Cacodemon resolves, ETB, and his trigger for destroying other creatures goes off but it then does not also tap your own creatures? I was thinking of cards like Stifle and Trickbind - I mean I guess someone could let their own creatures die, and then Stifle to counter the "then tap all other creatures you control" part? Not sure if that is even possible or not. If it doesn't matter... then yeah, just need a way to have both effects happen on ETB when cast from hand.
escplan9
 
Posts: 257
Joined: 10 Aug 2015, 22:38
Has thanked: 26 times
Been thanked: 40 times

Re: Help implementing a card

Postby escplan9 » 29 Feb 2016, 19:49

Well... thinking about it more... I can't just hack it together with adding a tap effect to the ETB. This is one where the effect should stack properly.

Dread Cacodemon is cast from hand when he enters the battlefield...

STACK
Destroy all creatures you do not control
Tap all other creatures you control

I'll look around for other cards that have specific ordering for some ideas how to do this right. Or see if I can figure out what went wrong with LevelX's suggestions at the start.
escplan9
 
Posts: 257
Joined: 10 Aug 2015, 22:38
Has thanked: 26 times
Been thanked: 40 times

Re: Help implementing a card

Postby escplan9 » 29 Feb 2016, 20:19

Sorry for all the posts... very eager to get this card working. Looking back at LevelX's recommendation, that's more along the lines of what needs to be done. I think the only issue with that code was it used "CastFromHandCondition" without using "CastFromHandWatcher" - like if you look at CastFromHandCondition docs, it states:
Warning: CastFromHandWatcher must be installed to card for proper working.

I'll work on fixing it up. Thanks for the help everyone.

edit: I have LevelX's version doing something - but again the TapAllEffect is happening regardless of cast from hand or not. edit2: Huh... looks like it completely ignores the Cast From Hand check entirely. I reanimate and both triggers still happen. The only difference is when Cast From Hand, I get the small window asking me to organize the two triggers - which still doesn't seem right for that anyways. When reanimated, I do not get the window asking me to order the triggers.

Code: Select all
        TriggeredAbility triggeredAbility = new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(opponentsCreatures, false));
        Effect effect = new TapAllEffect(otherCreaturesYouControl);
        effect.setText("then tap all other creatures you control");
        triggeredAbility.addEffect(effect);
        this.addAbility(new ConditionalTriggeredAbility(triggeredAbility, new CastFromHandCondition(),
                "When {this} enters the battlefield, if you cast it from your hand, destroy all creatures your opponents control, then tap all other creatures you control."));
        this.addAbility(triggeredAbility, new CastFromHandWatcher());   
escplan9
 
Posts: 257
Joined: 10 Aug 2015, 22:38
Has thanked: 26 times
Been thanked: 40 times

Re: Help implementing a card

Postby Doctor Weird » 29 Feb 2016, 21:13

This might be of no help, mind you, as I don't really do Java and have never contributed with the implementation of cards myself (mostly because I know that once I let myself try and learn how to implement one card I'll just never stop and then there goes all of my free time, been there, done that with other similar coding endeavors, haha).

But I figured I would mention two already implemented cards that may, or may not help you learning by observation: Scion of Vitu-Ghazi, from Dragon's Maze, and Breaching Leviathan, from Commander 2014, as both of those have "cast from hand" requirements and subsequent effects that are split into two different actions. Have a look at their source code, you might find some light there.

And you absolutely do want to make sure the ability is done correctly, as in not making it two different effects going separately on the stack. Not only because that is how the rules demand it ("then" in card's rule texts means you do the next action after the previous but never with any other thing happening in between), but also because even if it might sound unlikely at first glance, there are always situations where these things could matter. From the top of my head I could already make up some scenarios. For example: you're in a multiplayer game, someone has a Iona, Shield of Emeria in play set to red, you have a Steely Resolve set to "Demon" and one non-demon creature in play, you cast your Dread Cacodemon, killing said Iona, but now, before your other creature was tapped, squeezed in there, between those two separate triggers on the stack, another player pulls out a Backlash aimed at that non-demon creature you control, dealing enough damage to kill you. Suddenly it mattered. Sure, absolutely crazy and convoluted scenario I just made up there, but theoretically possible, which is what matters in the end. I could also just go on with the myriad of possible consequences from things that would trigger when a creature dies going on top and resolving before your creatures are ever tapped. The list goes on and on.

Anyway, I'm sure you'll get it right eventually, keep it up and thanks for being another contributor. :D
Doctor Weird
 
Posts: 180
Joined: 25 May 2015, 01:33
Has thanked: 7 times
Been thanked: 52 times

Re: Help implementing a card

Postby escplan9 » 29 Feb 2016, 21:22

This is ugly, but works. If someone can confirm this is the proper handling according to the rules text for Dread Cacodemon , awesome:

Code: Select all
        Ability tapAllOtherCreaturesYouControl = new EntersBattlefieldTriggeredAbility(
                new ConditionalOneShotEffect(new TapAllEffect(otherCreaturesYouControl), new CastFromHandCondition(),
                " if you cast it from your hand, destroy all creatures your opponents control, then tap all other creatures you control."));       
       
        Ability destroyAllOpponentsCreatures = new EntersBattlefieldTriggeredAbility(
                new ConditionalOneShotEffect(new DestroyAllEffect(opponentsCreatures, false), new CastFromHandCondition(),
                " if you cast it from your hand, destroy all creatures your opponents control, then tap all other creatures you control."));
       
        this.addAbility(tapAllOtherCreaturesYouControl, new CastFromHandWatcher());
        this.addAbility(destroyAllOpponentsCreatures, new CastFromHandWatcher());
I think I'll leave the card at that for now. If anyone can improve upon it, go for it. This was the simplest way for me to figure out how to get the Cast From Hand to continually be reinforced correctly here. I'll hold off on sending it to the master branch and all that - just keeping it local since I'm not confident it is done correctly yet.
escplan9
 
Posts: 257
Joined: 10 Aug 2015, 22:38
Has thanked: 26 times
Been thanked: 40 times

Re: Help implementing a card

Postby escplan9 » 29 Feb 2016, 22:01

Thanks DoctorWeird, though it just makes me completely stumped. I've looked over various cards like Scion and Deathbringer Regent and the likes to get better ideas of how this is done. Scion was just like this:

Code: Select all
        Ability ability = new EntersBattlefieldTriggeredAbility(
                new ConditionalOneShotEffect(new TapAllEffect(otherCreaturesYouControl), new CastFromHandCondition(),
                " if you cast it from your hand, destroy all creatures your opponents control, THEN tap all other creatures you control."));
        ability.addEffect(new DestroyAllEffect(opponentsCreatures, false));
        this.addAbility(ability, new CastFromHandWatcher());   
Has the first condition followed by the "then" effect. When I test this though, it fails on the "when NOT cast from hand" cases. Right now the only working version I have for both cases "cast from hand" and "not cast from hand" is the two ETB triggers.

edit: uh nevermind. Now I cannot consistently get any version to enforce the "when cast from hand" condition. I give up for tonight. My best guess is at this point that the "cast from hand" watchers are bugged.

edit2: No clue. Works again consistently with the 2 ETB trigger version - though the ability ordering is messed up, taps my guys then kills their creatures. Head hurts from trying to figure out this mess.
escplan9
 
Posts: 257
Joined: 10 Aug 2015, 22:38
Has thanked: 26 times
Been thanked: 40 times

Re: Help implementing a card

Postby escplan9 » 01 Mar 2016, 00:09

Perhaps some of my issues is sometimes I may not have stopped the server instance. I've been trying to alter the tooltip text so I can know it is the version I believe I am testing. So I make the change to the tooltip to let me know, then I save the file and rebuild Mage set. Then I rebuild MAge server. then I run the server and finally the client to test.

The results:
Version 1: two ETB effects
Code: Select all
        Ability tapAllOtherCreaturesYouControl = new EntersBattlefieldTriggeredAbility(
                new ConditionalOneShotEffect(new TapAllEffect(otherCreaturesYouControl), new CastFromHandCondition(),
                " TAP STUFF"));       
               
        Ability destroyAllOpponentsCreatures = new EntersBattlefieldTriggeredAbility(
                new ConditionalOneShotEffect(new DestroyAllEffect(opponentsCreatures, false), new CastFromHandCondition(),
                " DESTROY STUFF"));
       
        this.addAbility(destroyAllOpponentsCreatures, new CastFromHandWatcher());       
        this.addAbility(tapAllOtherCreaturesYouControl, new CastFromHandWatcher());     
This allows the player to order the triggers, which is wrong, but there are two separate triggers on the stack at least. When the card is not cast from the hand, no triggers occur which is good.

Version 2: 1 ETB Effect, Destroy then add effect for Tap
Code: Select all
        Ability ability = new EntersBattlefieldTriggeredAbility(
                new ConditionalOneShotEffect(new DestroyAllEffect(opponentsCreatures, false), new CastFromHandCondition(),
                " TEST DESTROY TAP"));
        ability.addEffect(new TapAllEffect(otherCreaturesYouControl));
        this.addAbility(ability, new CastFromHandWatcher());
No ordering of triggers is allowed, however both effects occur simultaneously so there is no way to respond before the "then" clause which is wrong. Additionally, when cheated into play by not casting it from the hand, in this case the added effect of Tapping occurs. So addEffect is ignoring the CastFromHand condition?

Version 3: 1 ETB Effect, Tap then add effect for Destroy
Code: Select all
        Ability ability = new EntersBattlefieldTriggeredAbility(
                new ConditionalOneShotEffect(new TapAllEffect(otherCreaturesYouControl), new CastFromHandCondition(),
                " TEST TAP DESTROY"));
        ability.addEffect(new DestroyAllEffect(opponentsCreatures, false));
        this.addAbility(ability, new CastFromHandWatcher());   
Again, no ordering of triggers is allowed, however both effects occur simultaneously so there is no way to respond before the "then" clause which is wrong. Additionally, when cheated into play by not casting it from the hand, in this case the added effect of Destroying occurs. So again, addEffect is ignoring the CastFromHand condition?

Any thoughts on this? What is wrong with the code I'm doing?

I haven't tested with cards like Scion for instance to see if perhaps there is a bigger bug with cards like Scion which use the code formatting of version 2 and 3 - there may be a bug with the card when it is not cast from the hand. It will still do the addEffect portion when it is NOT cast from hand I suspect.

Version 1 is the closest, but I should not be able to order the triggers.

edit: For reference here is the Scion of Vitu-Ghazi code -

Code: Select all
        // When Scion of Vitu-Ghazi enters the battlefield, if you cast it from your hand, put a 1/1 white Bird creature token with flying onto the battlefield, then populate.
        Ability ability = new EntersBattlefieldTriggeredAbility(
                new ConditionalOneShotEffect(new CreateTokenEffect(new BirdToken()), new CastFromHandCondition(),
                "if you cast it from your hand, put a 1/1 white Bird creature token with flying onto the battlefield,"));
        ability.addEffect(new PopulateEffect("then"));
        this.addAbility(ability, new CastFromHandWatcher());
You'll notice its structure is identical to my versions 2 and 3 just with different effects.
escplan9
 
Posts: 257
Joined: 10 Aug 2015, 22:38
Has thanked: 26 times
Been thanked: 40 times

Re: Help implementing a card

Postby escplan9 » 01 Mar 2016, 00:45

Confirmed the bug with Scion of Vitu-Ghazi - if it is NOT cast from the hand, it will still do the addEffect portion:

Code: Select all
        Ability ability = new EntersBattlefieldTriggeredAbility(
                new ConditionalOneShotEffect(new CreateTokenEffect(new BirdToken()), new CastFromHandCondition(),
                "if you cast it from your hand, put a 1/1 white Bird creature token with flying onto the battlefield,"));
        ability.addEffect(new PopulateEffect("then"));
        this.addAbility(ability, new CastFromHandWatcher());
edit 2: For the hell of it, tested the reverse ordering of actions for Scion of Vitu-Ghazi:
Code: Select all
        // VERSION 2: populate then add effect to create token
        Ability ability = new EntersBattlefieldTriggeredAbility(
                new ConditionalOneShotEffect(new PopulateEffect("then"), new CastFromHandCondition(),
                "POPULATE FIRST"));
        ability.addEffect(new CreateTokenEffect(new BirdToken()));
        this.addAbility(ability, new CastFromHandWatcher()); 
As shown before, the addEffect still occurs when NOT cast from hand. So here it would create a token as Scion is reanimated or otherwise cheated into play.

I submitted a bug report on Scion. I wonder how many other cards are affected by this... also makes me wonder what I'm supposed to do with Dread Cacodemon :(
Last edited by escplan9 on 01 Mar 2016, 15:57, edited 1 time in total.
escplan9
 
Posts: 257
Joined: 10 Aug 2015, 22:38
Has thanked: 26 times
Been thanked: 40 times

Re: Help implementing a card

Postby escplan9 » 01 Mar 2016, 01:37

Went back to the original version recommended by LevelX and it also behaves differently than the others:
Code: Select all
        TriggeredAbility triggeredAbility = new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(opponentsCreatures, false));
        Effect effect = new TapAllEffect(otherCreaturesYouControl);
        effect.setText("TAP TAP TAP");
        triggeredAbility.addEffect(effect);
        this.addAbility(new ConditionalTriggeredAbility(triggeredAbility, new CastFromHandCondition(),
                "DESTROY FULL."));
        this.addAbility(triggeredAbility, new CastFromHandWatcher());   
When the demon enters, you are asked to order the two triggered effects. And when you cheat him into play (NOT cast from hand), both effects go off (destroy and tap) without being asked to order any triggered effects.

If we do not want people to be able to respond to either of the effects - they go off immediately after the other without interruption, we need to fix the Cast from Hand portions. I'm not sure what else to do with the card at this time.
escplan9
 
Posts: 257
Joined: 10 Aug 2015, 22:38
Has thanked: 26 times
Been thanked: 40 times

Re: Help implementing a card

Postby escplan9 » 01 Mar 2016, 07:27

Good news everyone - I may shut up soon enough! :D

In looking at other examples of cards where there were multiple effects to occur upon cast, I found some that created another class CardNameEffect() that added the handling in there. I decided to go that route after all the frustration yesterday. I based it off the structure in the card Breaching Leviathan.

Tested and works correctly both when cast from hand (applies effects in the correct order without allowing any response) and when not cast from hand (no effects apply).

Code: Select all
        Ability ability = new EntersBattlefieldTriggeredAbility(
                new ConditionalOneShotEffect(new DreadCacodemonEffect(), new CastFromHandCondition(),
                " if you cast it from your hand, destroy all creatures your opponents control, then tap all other creatures you control."));
        this.addAbility(ability, new CastFromHandWatcher());

...

    public DreadCacodemonEffect() {
        super(Outcome.DestroyPermanent);
        this.staticText = "destroy all creatures your opponents control, then tap all other creatures you control";
    }

...

    @Override
    public boolean apply(Game game, Ability source) {
        for (Permanent creature: game.getBattlefield().getActivePermanents(opponentsCreatures, source.getControllerId(), source.getSourceId(), game)) {
            creature.destroy(source.getSourceId(), game, false);
        }
       
        for (Permanent creature: game.getBattlefield().getActivePermanents(otherCreaturesYouControl, source.getControllerId(), source.getSourceId(), game)) {
            creature.tap(game);
        }
        return true;
    }
Not sure on the Outcome constant - assuming it just means "as long as a permanent was destroyed, then tap other creatures you control"? And then hopefully I did the overriding apply function correctly - the creature.destroy part mostly. I believe getSourceID() is what I want for UUID here if I'm understanding it right.

edit: Created pull request (drmDev).
escplan9
 
Posts: 257
Joined: 10 Aug 2015, 22:38
Has thanked: 26 times
Been thanked: 40 times

PreviousNext

Return to Developers Talk

Who is online

Users browsing this forum: No registered users and 7 guests


Who is online

In total there are 7 users online :: 0 registered, 0 hidden and 7 guests (based on users active over the past 10 minutes)
Most users ever online was 4143 on 23 Jan 2024, 08:21

Users browsing this forum: No registered users and 7 guests

Login Form