It is currently 09 Sep 2025, 17:52
   
Text Size

enControlCreature

Post MTG Forge Related Programming Questions Here

Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins

enControlCreature

Postby Chris H. » 02 May 2010, 17:41

This is a fairly simple keyword which takes the code from Control Magic and makes a few modifications which in turn allows a few new cards. This keyword is an early version and will need additional work to implement the last of the cards which could make use of this keyword.

The simplest form of this keyword is:

Code: Select all
enControlCreature
`
and Control Magic and similar spells use this form. The next form:

Code: Select all
enControlCreature:{options}
`
allows several more cards such as Mind Harness and Threads of Disloyalty. I kept the {options} code to a minimum and they serve as a code stub for further expansion in case similar cards are released in the future. The three versions of {options} that are recognized at this time are:

Code: Select all
Option=CMC 2 or less
Option=red or green
Option=untap up to 5 lands
`
The code which tests for these three options will also look for these three new keywords:

Code: Select all
Enchant creature with converted mana cost 2 or less
Enchant red or green creature
When CARDNAME enters the battlefield, untap up to five lands.
`
and either form will work. I included both … just for the heck of it.

I did not include the section of code which allows Flash to be used with enControlCreature. If a need arises we can use the code from CardFactory_Util.enPump_Enchant().

I also did not include code for spell description or stack description. This also can be added at a later time if a need arises.

These are the new entries for the cards which use this keyword:

Code: Select all
Binding Grasp
3 U
Enchantment Aura
You control enchanted creature. Enchanted creature gets +0/+1.
Enchant creature
At the beginning of your upkeep, sacrifice Binding Grasp unless you pay:1 U
enControlCreature
enPump:+0/+1

Control Magic
2 U U
Enchantment Aura
You control enchanted creature.
Enchant creature
enControlCreature

Mind Control
3 U U
Enchantment Aura
You control enchanted creature.
Enchant creature
enControlCreature

Mind Harness
U
Enchantment Aura
You control enchanted creature.
Enchant red or green creature
Cumulative upkeep:1
enControlCreature::Option=red or green

Persuasion
3 U U
Enchantment Aura
You control enchanted creature.
Enchant creature
enControlCreature

Threads of Disloyalty
1 U U
Enchantment Aura
You control enchanted creature.
enControlCreature:Option=CMC 2 or less
Enchant creature with converted mana cost 2 or less

Treachery
3 U U
Enchantment Aura
You control enchanted creature.
Enchant creature
enControlCreature:Option=untap up to 5 lands
When CARDNAME enters the battlefield, untap up to five lands.

Yavimaya's Embrace
5 G U U
Enchantment Aura
You control enchanted creature. Enchanted creature gets +2/+2 and has trample.
Enchant creature
enPump:+2/+2/Trample
enControlCreature
`
I discovered that I was able to have the enPump and the enControlCreature keyword applied to the same card. :D The aura Yavimaya's Embrace works correctly. It does not bring up a choice window for us to select which of the two abilities to select. Both keywords are applied when the spell resolves. =D>

There are six additional cards that could be implemented which would require code in other class files. I have no plans to add these cards myself at this time:

Code: Select all
Abduction
2UU
Enchantment — Aura
Enchant creature
When Abduction enters the battlefield, untap enchanted creature.
You control enchanted creature.
When enchanted creature is put into a graveyard, return that card to the battlefield under its owner's control.

Biting Tether
4U
Enchantment — Aura
Enchant creature
You control enchanted creature.
At the beginning of your upkeep, put a -1/-1 counter on enchanted creature.

Enslave
4BB
Enchantment — Aura
Enchant creature
You control enchanted creature.
At the beginning of your upkeep, enchanted creature deals 1 damage to its owner.

Krovikan Whispers
3U
Enchantment — Aura
Enchant creature
Cumulative upkeep {U} or {B} (At the beginning of your upkeep, put an age counter on this permanent, then sacrifice it unless you pay its upkeep cost for each age counter on it.)
You control enchanted creature.
When Krovikan Whispers is put into a graveyard from the battlefield, you lose 2 life for each age counter on it.

Mark of the Oni
2B
Enchantment — Aura
Enchant creature
You control enchanted creature.
At the beginning of the end step, if you control no Demons, sacrifice Mark of the Oni.

Vapor Snare
4U
Enchantment — Aura
Enchant creature
You control enchanted creature.
At the beginning of your upkeep, sacrifice Vapor Snare unless you return a land you control to its owner's hand.
User avatar
Chris H.
Forge Moderator
 
Posts: 6320
Joined: 04 Nov 2008, 12:11
Location: Mac OS X Yosemite
Has thanked: 644 times
Been thanked: 643 times

Re: enControlCreature

Postby Rob Cashwalker » 02 May 2010, 20:12

Nice job! =D>

You didn't post the code, so I can't comment specifically, but I'd like to see the keyword trigger off something like "enTakeControl" and then you check for "Type.Creature" or "Type.Artifact" (etc...) and "CMC.2" or "Color.Red|Green" (etc...) as individual parameters.

Future keyword - "spTakeControl" with options like "UntilEOT" or "SacEOT"
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: enControlCreature

Postby Chris H. » 02 May 2010, 21:43

Rob Cashwalker wrote:Nice job! =D>

You didn't post the code, so I can't comment specifically, but I'd like to see the keyword trigger off something like "enTakeControl" and then you check for "Type.Creature" or "Type.Artifact" (etc...) and "CMC.2" or "Color.Red|Green" (etc...) as individual parameters.

Future keyword - "spTakeControl" with options like "UntilEOT" or "SacEOT"
`
Yeah, we kind of take these things one small step at a time. :wink: This effort is not too bad considering I'm just a jr. coder in training ... although I feel like the training wheels are coming off.

The code block is kind of long. I will go ahead and post it. Most people will quickly find themselves getting lost. :rolleyes:

Code: Select all
        /*
         *  For Control Magic type of auras
         */
        if (shouldControl(card) != -1) {
            int n = shouldControl(card);
            if (n != -1) {
                String parse = card.getKeyword().get(n).toString();
                card.removeIntrinsicKeyword(parse);
                String k[] = parse.split(":");
               
                String option = "none";
                boolean optionUnTapLands = false;
                final boolean optionCmcTwoOrLess[] = {false};
                final boolean optionRedOrGreen[] = {false};
               
                /*
                 *  Check to see if these are options and/or descriptions
                 */
                if (k.length > 1) {
                   if (k[1].startsWith("Option=")) {
                      option = k[1].substring(7);
                   }
                }
               
                /*
                 *  This is for the Treachery aura
                 *  no need to parse the number of lands at this time
                 */
                if (option.contains("untap up to 5 lands") ||
                      card.getKeyword().contains("When CARDNAME enters the battlefield, untap up to five lands.")) {
                   optionUnTapLands = true;
                }
               
                /*
                 *  This is for the Threads of Disloyalty aura
                 *  no need to parse the CMC number at this time
                 */
                if (option.contains("CMC 2 or less") ||
                      card.getKeyword().contains("Enchant creature with converted mana cost 2 or less")) {
                   optionCmcTwoOrLess[0] = true;
                }
               
                /*
                 *  This is for the Mind Harness aura
                 *  no need to parse the colors at this time
                 */
                if (option.contains("red or green") ||
                      card.getKeyword().contains("Enchant red or green creature")) {
                   optionRedOrGreen[0] = true;
                }
               
                /*
                 *  I borrowed the code from Peregrine Drake
                 */
                final Input untap = new Input() {
               private static final long serialVersionUID = -2208979487849617156L;
               int                       stop             = 5;
                    int                       count            = 0;
                   
                    @Override
                    public void showMessage() {
                        AllZone.Display.showMessage("Select a land to untap");
                        ButtonUtil.enableOnlyCancel();
                    }
                   
                    @Override
                    public void selectButtonCancel() {
                        stop();
                    }
                   
                    @Override
                    public void selectCard(Card card, PlayerZone zone) {
                        if(card.isLand() && zone.is(Constant.Zone.Play)) {
                            card.untap();
                            count++;
                            if(count == stop) stop();
                        }
                    }//selectCard()
                };// Input untap
               
                final SpellAbility untapAbility = new Ability(card, "0") {
                    @Override
                    public void resolve() {
                        if(card.getController().equals("Human")) AllZone.InputControl.setInput(untap);
                        else {
                            CardList list = new CardList(AllZone.Computer_Play.getCards());
                            list = list.filter(new CardListFilter() {
                                public boolean addCard(Card c) {
                                    return c.isLand() && c.isTapped();
                                }
                            });
                            for(int i = 0; i < 5 && i < list.size(); i++)
                                list.get(i).untap();
                        }//else
                    }//resolve()
                };// untapAbility
               
                Command intoPlay = new Command() {
               private static final long serialVersionUID = -3310362768233358111L;

               public void execute() {
                       untapAbility.setStackDescription(card.getController() + " untaps up to 5 lands.");
                        AllZone.Stack.add(untapAbility);
                    }
                };
                if (optionUnTapLands) {
                   card.addComesIntoPlayCommand(intoPlay);
                }
               
                /*
                 *  I borrowed this code from Control Magic
                 */
                final SpellAbility spell = new Spell(card) {
               private static final long serialVersionUID = 5211276723523636356L;

               @Override
                    public boolean canPlayAI() {
                        CardList tgts = CardFactoryUtil.AI_getHumanCreature(card, true);
                        CardListUtil.sortAttack(tgts);
                        CardListUtil.sortFlying(tgts);
                       
                        /*
                         *  This is a new addition and is used
                         *  by the Threads of Disloyalty aura
                         */
                        if (optionCmcTwoOrLess[0]) {
                           tgts = tgts.filter(new CardListFilter() {
                              public boolean addCard(Card c) {
                                 return CardUtil.getConvertedManaCost(c.getManaCost()) <= 2;
                              }
                           });
                           if (tgts.isEmpty()) return false;
                           else {
                              CardListUtil.sortAttack(tgts);
                                CardListUtil.sortFlying(tgts);
                              setTargetCard(tgts.get(0));
                              return true;
                           }
                        }
                       
                        /*
                         *  This is a new addition and is
                         *  used by the Mind Harness aura
                         */
                        if (optionRedOrGreen[0]) {
                           tgts = tgts.filter(new CardListFilter() {
                              public boolean addCard(Card c) {
                                 return CardUtil.getColors(c).contains(Constant.Color.Green) ||
                                 CardUtil.getColors(c).contains(Constant.Color.Red);
                              }
                           });
                        }
                       
                        if (tgts.isEmpty()) return false;
                                               
                        if (2 <= tgts.get(0).getNetAttack() && tgts.get(0).getKeyword().contains("Flying")) {
                            setTargetCard(tgts.get(0));
                            return true;
                        }
                       
                        CardListUtil.sortAttack(tgts);
                        if (4 <= tgts.get(0).getNetAttack()) {
                            setTargetCard(tgts.get(0));
                            return true;
                        }
                       
                        /*
                         *  This is new and we may want to add more tests
                         *  Do we want the AI to hold these auras when
                         *  losing game and at a creature disadvatange
                         */
                        if (3 <= tgts.get(0).getNetAttack() && AllZone.Human_Life.getLife() > AllZone.Computer_Life.getLife()) {
                            setTargetCard(tgts.get(0));
                            return true;
                        }
                       
                        return false;
                    }//canPlayAI()
                   
                    @Override
                    public void resolve() {
                        PlayerZone play = AllZone.getZone(Constant.Zone.Play, card.getController());
                        play.add(card);
                       
                        Card c = getTargetCard();
                       
                        if (AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(card, c)) card.enchantCard(c);
                       
                    }//resolve()
                };//SpellAbility
                card.clearSpellAbility();
                card.addSpellAbility(spell);
               
                Command onEnchant = new Command() {
               private static final long serialVersionUID = -6323085271405286813L;

               public void execute() {
                        if(card.isEnchanting()) {
                            Card crd = card.getEnchanting().get(0);
                            //set summoning sickness
                            if(crd.getKeyword().contains("Haste")) {
                                crd.setSickness(false);
                            } else {
                                crd.setSickness(true);
                            }
                           
                            ((PlayerZone_ComesIntoPlay) AllZone.Human_Play).setTriggers(false);
                            ((PlayerZone_ComesIntoPlay) AllZone.Computer_Play).setTriggers(false);
                           
                            PlayerZone from = AllZone.getZone(crd);
                            from.remove(crd);
                           
                            crd.setController(card.getController());
                           
                            PlayerZone to = AllZone.getZone(Constant.Zone.Play, card.getController());
                            to.add(crd);
                           
                            ((PlayerZone_ComesIntoPlay) AllZone.Human_Play).setTriggers(true);
                            ((PlayerZone_ComesIntoPlay) AllZone.Computer_Play).setTriggers(true);
                        }
                    }//execute()
                };//Command
               
                Command onUnEnchant = new Command() {
               private static final long serialVersionUID = -3086710987052359078L;

               public void execute() {
                        if(card.isEnchanting()) {
                            Card crd = card.getEnchanting().get(0);
                            if(AllZone.GameAction.isCardInPlay(crd)) {
                                if(crd.getKeyword().contains("Haste")) {
                                    crd.setSickness(false);
                                } else {
                                    crd.setSickness(true);
                                }
                               
                                ((PlayerZone_ComesIntoPlay) AllZone.Human_Play).setTriggers(false);
                                ((PlayerZone_ComesIntoPlay) AllZone.Computer_Play).setTriggers(false);
                               
                                PlayerZone from = AllZone.getZone(crd);
                                from.remove(crd);
                               
                                AllZone.Combat.removeFromCombat(crd);
                               
                                String opp = AllZone.GameAction.getOpponent(crd.getController());
                                crd.setController(opp);
                               
                                PlayerZone to = AllZone.getZone(Constant.Zone.Play, opp);
                                to.add(crd);
                               
                                ((PlayerZone_ComesIntoPlay) AllZone.Human_Play).setTriggers(true);
                                ((PlayerZone_ComesIntoPlay) AllZone.Computer_Play).setTriggers(true);
                            }
                        }
                       
                    }//execute()
                };//Command
               
                Command onLeavesPlay = new Command() {
               private static final long serialVersionUID = 7464815269438815827L;

               public void execute() {
                        if(card.isEnchanting()) {
                            Card crd = card.getEnchanting().get(0);
                            card.unEnchantCard(crd);
                        }
                    }
                };//Command
               
                /*
                 *  We now need an improved input method so we can filter out the inappropriate
                 *  choices for the auras Threads of Disloyalty and Mind Harness
                 *
                 *  NOTE: can we target a creature in our zone ?
                 */
                Input runtime = new Input() {
                    private static final long serialVersionUID = -7462101446917907106L;

                    @Override
                    public void showMessage() {
                        PlayerZone comp = AllZone.getZone(Constant.Zone.Play, Constant.Player.Computer);
                        PlayerZone hum = AllZone.getZone(Constant.Zone.Play, Constant.Player.Human);
                        CardList creatures = new CardList();
                        creatures.addAll(comp.getCards());
                        creatures.addAll(hum.getCards());
                        creatures = creatures.filter(new CardListFilter() {
                            public boolean addCard(Card c) {
                                return c.isCreature() && CardFactoryUtil.canTarget(card, c) &&
                                ((!optionCmcTwoOrLess[0]) || (optionCmcTwoOrLess[0] && CardUtil.getConvertedManaCost(c.getManaCost()) <= 2)) &&
                                ((!optionRedOrGreen[0]) || (optionRedOrGreen[0] &&
                                   CardUtil.getColors(c).contains(Constant.Color.Green) || CardUtil.getColors(c).contains(Constant.Color.Red)));
                            }
                        });
                       
                        stopSetNext(CardFactoryUtil.input_targetSpecific(spell, creatures, "Select target creature", true, false));
                    }
                };
               
                card.addEnchantCommand(onEnchant);
                card.addUnEnchantCommand(onUnEnchant);
                card.addLeavesPlayCommand(onLeavesPlay);
               
                spell.setBeforePayMana(runtime);
            }// SpellAbility spell
        }// enControlCreature
User avatar
Chris H.
Forge Moderator
 
Posts: 6320
Joined: 04 Nov 2008, 12:11
Location: Mac OS X Yosemite
Has thanked: 644 times
Been thanked: 643 times


Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 47 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 47 users online :: 0 registered, 0 hidden and 47 guests (based on users active over the past 10 minutes)
Most users ever online was 7303 on 15 Jul 2025, 20:46

Users browsing this forum: No registered users and 47 guests

Login Form