enControlCreature
Post MTG Forge Related Programming Questions Here
Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins
3 posts
• Page 1 of 1
enControlCreature
by 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:
and Control Magic and similar spells use this form. The next form:
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:
The code which tests for these three options will also look for these three new keywords:
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:
I discovered that I was able to have the enPump and the enControlCreature keyword applied to the same card.
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.
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:
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.


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.
-
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
by Rob Cashwalker » 02 May 2010, 20:12
Nice job!
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"

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.
-
Rob Cashwalker - Programmer
- Posts: 2167
- Joined: 09 Sep 2008, 15:09
- Location: New York
- Has thanked: 5 times
- Been thanked: 40 times
Re: enControlCreature
by Chris H. » 02 May 2010, 21:43
`Rob Cashwalker wrote:Nice job!![]()
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.

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

- 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
-
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
3 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 47 guests