- Added AI logic to play a simple Illusions-Donate Trix deck.

- Added a quest opponent The Great and Powerful Trixie 4, a mono blue Trix combo deck with Illusions of Grandeur and Donate and a wide array of permission. It may be a little haphazard and not always very consistent, but it does beat many hard and very hard opponents with a decent chance.
This commit is contained in:
Agetian
2017-01-04 18:48:56 +00:00
parent 70ada910be
commit 2853fcc200
6 changed files with 99 additions and 3 deletions

1
.gitattributes vendored
View File

@@ -18987,6 +18987,7 @@ forge-gui/res/quest/duels/Terminator[!!-~]3.dck -text
forge-gui/res/quest/duels/Thanos[!!-~]3.dck -text
forge-gui/res/quest/duels/The[!!-~]Great[!!-~]Gatsby[!!-~]1.dck -text
forge-gui/res/quest/duels/The[!!-~]Great[!!-~]Gazoo[!!-~]3.dck -text
forge-gui/res/quest/duels/The[!!-~]Great[!!-~]and[!!-~]Powerful[!!-~]Trixie[!!-~]4.dck -text
forge-gui/res/quest/duels/The[!!-~]Nac[!!-~]Mac[!!-~]Feegle[!!-~]3.dck -text
forge-gui/res/quest/duels/The[!!-~]Shade[!!-~]3.dck -text
forge-gui/res/quest/duels/The[!!-~]Spectre[!!-~]3.dck -text

View File

@@ -19,6 +19,7 @@ import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import org.apache.commons.lang3.StringUtils;
public class PermanentAi extends SpellAbilityAi {
@@ -150,6 +151,46 @@ public class PermanentAi extends SpellAbilityAi {
}
}
}
// check for specific AI preferences
if (card.hasSVar("AICastPreference")) {
String pref = card.getSVar("AICastPreference");
String[] groups = StringUtils.split(pref, "|");
for (String group : groups) {
String[] elems = StringUtils.split(group.trim(), '$');
String param = elems[0].trim();
String value = elems[1].trim();
if (param.equals("MustHaveInHand")) {
// Only cast if another card is present in hand (e.g. Illusions of Grandeur followed by Donate)
boolean hasCard = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.nameEquals(value)).size() > 0;
if (!hasCard) {
return false;
}
} else if (param.equals("MaxControlled")) {
// Only cast unless there are X or more cards like this on the battlefield under AI control already
int numControlled = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.nameEquals(card.getName())).size();
if (numControlled >= Integer.parseInt(value)) {
return false;
}
} else if (elems[0].trim().equals("NumManaSources")) {
// Only cast if there are X or more mana sources controlled by the AI
CardCollection m = ComputerUtilMana.getAvailableMana(ai, true);
if (m.size() < Integer.parseInt(value)) {
return false;
}
} else if (elems[0].trim().equals("NumManaSourcesNextTurn")) {
// Only cast if there are X or more mana sources controlled by the AI *or*
// if there are X-1 mana sources in play but the AI has an extra land in hand
CardCollection m = ComputerUtilMana.getAvailableMana(ai, true);
int hasExtraLandInHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.LANDS).size() > 0 ? 1 : 0;
if (m.size() + hasExtraLandInHand < Integer.parseInt(value)) {
return false;
}
}
}
}
return true;
}

View File

@@ -5,6 +5,7 @@ import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CounterType;
import forge.game.card.CardPredicates.Presets;
@@ -93,6 +94,20 @@ public class PumpAi extends PumpAiBase {
sa.getTargets().add(lowest);
return true;
}
} else if (sa.hasParam("AILogic") && sa.getParam("AILogic").startsWith("Donate")) {
// Donate currently supports only one special code path (Illusions of Grandeur)
CardCollectionView aiList = ai.getCardsIn(ZoneType.Battlefield, "Illusions of Grandeur");
if (aiList.size() > 0) {
// Donate an Illusions of Grandeur, step 1 - target the opponent.
if (sa.getParam("AILogic").equals("DonateTargetPlayer")) {
sa.resetTargets();
sa.getTargets().add(ai.getOpponents().get(0)); // TODO: expand this to donate to an opp who doesn't have Illusions yet
return true;
}
}
// AI currently does not know how to handle Donate effectively otherwise
// TODO: enhance this for other cases (e.g. Donating a card with bad drawback to the opponent)
return false;
}
if (ComputerUtil.preventRunAwayActivations(sa)) {
@@ -233,6 +248,13 @@ public class PumpAi extends PumpAiBase {
} else {
return false;
}
} else if (sa.getParam("AILogic").equals("DonateTargetPerm")) {
// Illusions of Grandeur + Donate, step 2 - target Illusions.
CardCollectionView aiList = ai.getCardsIn(ZoneType.Battlefield, "Illusions of Grandeur");
if (aiList.size() > 0) {
sa.getTargets().add(aiList.get(0));
return true;
}
}
if (isFight) {
return FightAi.canFightAi(ai, sa, attack, defense);

View File

@@ -1,9 +1,9 @@
Name:Donate
ManaCost:2 U
Types:Sorcery
A:SP$ Pump | Cost$ 2 U | ValidTgts$ Player | TgtPrompt$ Select target player | SubAbility$ D1 | SpellDescription$ Target player gains control of target permanent you control. | StackDescription$ None
A:SP$ Pump | Cost$ 2 U | ValidTgts$ Player | TgtPrompt$ Select target player | SubAbility$ D1 | AILogic$ DonateTargetPlayer | SpellDescription$ Target player gains control of target permanent you control. | StackDescription$ None
SVar:D1:DB$ Pump | RememberObjects$ Targeted | Static$ True | SubAbility$ D2 | StackDescription$ None
SVar:D2:DB$ Pump | ValidTgts$ Permanent.YouCtrl | TgtPrompt$ Select target permanent you control | SubAbility$ D3 | StackDescription$ None
SVar:D2:DB$ Pump | ValidTgts$ Permanent.YouCtrl | TgtPrompt$ Select target permanent you control | SubAbility$ D3 | AILogic$ DonateTargetPerm | StackDescription$ None
SVar:D3:DB$ GainControl | Defined$ Targeted | NewController$ Remembered | SubAbility$ D4
SVar:D4:DB$ Cleanup | ClearRemembered$ True
SVar:RemRandomDeck:True

View File

@@ -6,6 +6,9 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.S
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigLoseLife | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME leaves the battlefield, you lose 20 life.
SVar:TrigGainLife:AB$GainLife | Cost$ 0 | Defined$ TriggeredCardController | LifeAmount$ 20
SVar:TrigLoseLife:AB$LoseLife | Cost$ 0 | Defined$ TriggeredCardController | LifeAmount$ 20
SVar:RemAIDeck:True
SVar:AICastPreference:MustHaveInHand$ Donate | MaxControlled$ 1 | NumManaSourcesNextTurn$ 5
SVar:RemRandomDeck:True
SVar:DeckNeeds:Name$Donate
SVar:PlayMain1:TRUE
SVar:Picture:http://www.wizards.com/global/images/magic/general/illusions_of_grandeur.jpg
Oracle:Cumulative upkeep {2} (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.)\nWhen Illusions of Grandeur enters the battlefield, you gain 20 life.\nWhen Illusions of Grandeur leaves the battlefield, you lose 20 life.

View File

@@ -0,0 +1,29 @@
[duel]
[metadata]
Name=The Great and Powerful Trixie 4
Title=The Great and Powerful Trixie
Difficulty=very hard
Description=Mono Blue Trix combo deck with Illusions of Grandeur and Donate
Icon=Great and Powerful Trixie.jpg
Deck Type=constructed
[main]
1 Ancestral Recall
4 Arcane Denial
4 Counterspell
1 Dig Through Time
2 Disdainful Stroke
4 Donate
2 Essence Scatter
4 Illusions of Grandeur
15 Island
4 Mana Leak
1 Mox Emerald
1 Mox Jet
1 Mox Pearl
1 Mox Ruby
1 Mox Sapphire
4 Propaganda
4 Sapphire Medallion
1 Treasure Cruise
3 Unsummon
4 Vapor Snag