- Basic AI for AF Learn

- Some minor tweaks and fixes for AF Learn
This commit is contained in:
Hans Mackowiak
2021-04-07 05:11:55 +00:00
committed by Michael Kamensky
parent 5b77205b77
commit 0627d37f69
36 changed files with 382 additions and 17 deletions

View File

@@ -32,6 +32,7 @@ import com.google.common.collect.Lists;
import forge.ai.ability.ChangeZoneAi;
import forge.ai.ability.ExploreAi;
import forge.ai.ability.LearnAi;
import forge.ai.simulation.SpellAbilityPicker;
import forge.card.MagicColor;
import forge.card.mana.ManaCost;
@@ -2095,8 +2096,11 @@ public class AiController {
if (useSimulation) {
return simPicker.chooseCardToHiddenOriginChangeZone(destination, origin, sa, fetchList, player2, decider);
}
if (sa.getApi() == ApiType.Explore) {
return ExploreAi.shouldPutInGraveyard(fetchList, decider);
} else if (sa.getApi() == ApiType.Learn) {
return LearnAi.chooseCardToLearn(fetchList, decider, sa);
} else {
return ChangeZoneAi.chooseCardToHiddenOriginChangeZone(destination, origin, sa, fetchList, player2, decider);
}

View File

@@ -95,6 +95,7 @@ public enum SpellApiToAi {
.put(ApiType.Haunt, HauntAi.class)
.put(ApiType.ImmediateTrigger, ImmediateTriggerAi.class)
.put(ApiType.Investigate, InvestigateAi.class)
.put(ApiType.Learn, LearnAi.class)
.put(ApiType.LoseLife, LifeLoseAi.class)
.put(ApiType.LosesGame, GameLossAi.class)
.put(ApiType.Mana, ManaEffectAi.class)

View File

@@ -0,0 +1,56 @@
package forge.ai.ability;
import forge.ai.ComputerUtilCard;
import forge.ai.PlayerControllerAi;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
public class LearnAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {
// For the time being, Learn is treated as universally positive due to being optional
return true;
}
@Override
protected boolean doTriggerAINoCost(Player aiPlayer, SpellAbility sa, boolean mandatory) {
return mandatory || canPlayAI(aiPlayer, sa);
}
@Override
public boolean chkAIDrawback(SpellAbility sa, Player aiPlayer) {
return canPlayAI(aiPlayer, sa);
}
@Override
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
return true;
}
public static Card chooseCardToLearn(CardCollection options, Player ai, SpellAbility sa) {
CardCollection sideboard = CardLists.filter(options, CardPredicates.inZone(ZoneType.Sideboard));
CardCollection hand = CardLists.filter(options, CardPredicates.inZone(ZoneType.Hand));
hand.remove(sa.getHostCard()); // this card will be used in the process, don't consider it for discard
CardCollection lessons = CardLists.filter(sideboard, CardPredicates.isType("Lesson"));
CardCollection goodDiscards = ((PlayerControllerAi)ai.getController()).getAi().getCardsToDiscard(1, 1, hand, sa);
if (!lessons.isEmpty()) {
return ComputerUtilCard.getBestAI(lessons);
} else if (!goodDiscards.isEmpty()) {
return ComputerUtilCard.getWorstAI(goodDiscards);
}
// Don't choose anything if there's no good option
return null;
}
}

View File

@@ -11,6 +11,7 @@ import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCost;
import forge.ai.ability.ChangeZoneAi;
import forge.ai.ability.ExploreAi;
import forge.ai.ability.LearnAi;
import forge.ai.simulation.GameStateEvaluator.Score;
import forge.game.Game;
import forge.game.ability.ApiType;
@@ -423,6 +424,8 @@ public class SpellAbilityPicker {
}
if (sa.getApi() == ApiType.Explore) {
return ExploreAi.shouldPutInGraveyard(fetchList, decider);
} else if (sa.getApi() == ApiType.Learn) {
return LearnAi.chooseCardToLearn(fetchList, decider, sa);
} else {
return ChangeZoneAi.chooseCardToHiddenOriginChangeZone(destination, origin, sa, fetchList, player2, decider);
}

View File

@@ -134,7 +134,7 @@ public class GameFormat implements Comparable<GameFormat> {
if (!this.allowedSetCodes_ro.isEmpty()) {
p = Predicates.and(p, printed ?
IPaperCard.Predicates.printedInSets(this.allowedSetCodes_ro, printed) :
(Predicate<PaperCard>)(StaticData.instance().getCommonCards().wasPrintedInSets(this.allowedSetCodes_ro)));
StaticData.instance().getCommonCards().wasPrintedInSets(this.allowedSetCodes_ro));
}
if (!this.allowedRarities.isEmpty()) {
List<Predicate<? super PaperCard>> crp = Lists.newArrayList();

View File

@@ -93,6 +93,7 @@ public enum ApiType {
Haunt (HauntEffect.class),
Investigate (InvestigateEffect.class),
ImmediateTrigger (ImmediateTriggerEffect.class),
Learn (LearnEffect.class),
LookAt (LookAtEffect.class),
LoseLife (LifeLoseEffect.class),
LosesGame (GameLossEffect.class),

View File

@@ -4,6 +4,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Predicate;
@@ -942,6 +943,12 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
}
}
// for Wish cards, if the player is controlled by someone else
// they can't fetch from the outside the game/sideboard
if (player.isControlled()) {
origin.remove(ZoneType.Sideboard);
}
CardCollection fetchList;
boolean shuffleMandatory = true;
boolean searchedLibrary = false;
@@ -1179,6 +1186,9 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
}
}
boolean combatChanged = false;
final CardZoneTable triggerList = new CardZoneTable();
for (Player player : HiddenOriginChoicesMap.keySet()) {
boolean searchedLibrary = HiddenOriginChoicesMap.get(player).searchedLibrary;
boolean shuffleMandatory = HiddenOriginChoicesMap.get(player).shuffleMandatory;
@@ -1188,12 +1198,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
ZoneType destination = HiddenOriginChoicesMap.get(player).destination;
CardCollection movedCards = new CardCollection();
long ts = game.getNextTimestamp();
final CardZoneTable triggerList = new CardZoneTable();
boolean combatChanged = false;
Player decider = chooser;
if (decider == null) {
decider = player;
}
Player decider = ObjectUtils.firstNonNull(chooser, player);
for (final Card c : chosenCards) {
Card movedCard = null;
@@ -1423,15 +1428,15 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
registerDelayedTrigger(sa, sa.getParam("AtEOT"), movedCards);
}
if (combatChanged) {
game.updateCombatForView();
game.fireEvent(new GameEventCombatChanged());
}
triggerList.triggerChangesZoneAll(game);
}
if (combatChanged) {
game.updateCombatForView();
game.fireEvent(new GameEventCombatChanged());
}
triggerList.triggerChangesZoneAll(game);
if (sa.hasParam("UntilHostLeavesPlay")) {
source.addLeavesPlayCommand(untilHostLeavesPlayCommand(triggerList, source));
}
if (sa.hasParam("UntilHostLeavesPlay")) {
source.addLeavesPlayCommand(untilHostLeavesPlayCommand(triggerList, source));
}
}

View File

@@ -0,0 +1,27 @@
package forge.game.ability.effects;
import forge.game.Game;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardZoneTable;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
public class LearnEffect extends SpellAbilityEffect {
@Override
protected String getStackDescription(SpellAbility sa) {
return "Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)";
}
@Override
public void resolve(SpellAbility sa) {
final Card source = sa.getHostCard();
final Game game = source.getGame();
CardZoneTable table = new CardZoneTable();
for (Player p : getTargetPlayers(sa)) {
p.learnLesson(sa, table);
}
table.triggerChangesZoneAll(game);
}
}

View File

@@ -2667,6 +2667,11 @@ public class Player extends GameEntity implements Comparable<Player> {
return null;
}
public final boolean isControlled() {
Player ctrlPlayer = this.getControllingPlayer();
return ctrlPlayer != null && ctrlPlayer != this;
}
public void addController(long timestamp, Player pl) {
final IGameEntitiesFactory master = (IGameEntitiesFactory)pl.getLobbyPlayer();
addController(timestamp, pl, master.createMindSlaveController(pl, this), true);
@@ -3604,4 +3609,49 @@ public class Player extends GameEntity implements Comparable<Player> {
game.getAction().revealTo(revealCards, otherPlayers, Localizer.getInstance().getMessage("lblRevealFaceDownCards"));
}
}
public void learnLesson(SpellAbility sa, CardZoneTable table) {
// Replacement effects
Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
repParams.put(AbilityKey.Cause, sa);
if (game.getReplacementHandler().run(ReplacementType.Learn, repParams) != ReplacementResult.NotReplaced) {
return;
}
CardCollection list = new CardCollection();
if (!isControlled()) {
list.addAll(CardLists.getType(getZone(ZoneType.Sideboard), "Lesson"));
}
list.addAll(getZone(ZoneType.Hand));
if (list.isEmpty()) {
return;
}
Card c = getController().chooseSingleCardForZoneChange(ZoneType.Hand, ImmutableList.of(ZoneType.Sideboard, ZoneType.Hand),
sa, list, null, "Learn a Lesson", true, this);
if (c == null) {
return;
}
if (c.isInZone(ZoneType.Sideboard)) { // Sideboard Lesson to Hand
Card moved = game.getAction().moveTo(ZoneType.Hand, c, sa);
table.put(ZoneType.Sideboard, ZoneType.Hand, moved);
} else if (c.isInZone(ZoneType.Hand)) { // Discard and Draw
boolean firstDiscard = getNumDiscardedThisTurn() == 0;
if (discard(c, sa, table) != null) {
// Change this if something would make multiple player learn at the same time
// Discard Trigger outside Effect
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put(AbilityKey.Player, this);
runParams.put(AbilityKey.Cards, new CardCollection(c));
runParams.put(AbilityKey.Cause, sa);
runParams.put(AbilityKey.FirstTime, firstDiscard);
getGame().getTriggerHandler().runTrigger(TriggerType.DiscardedAll, runParams, false);
for (Card d : drawCards(1, sa)) {
table.put(ZoneType.Library, ZoneType.Hand, d); // does a ChangesZoneAll care about moving from Library to Hand
}
}
}
}
}

View File

@@ -485,6 +485,8 @@ public class PlayerView extends GameEntityView {
return TrackableProperty.Library;
case Flashback:
return TrackableProperty.Flashback;
case Sideboard:
return TrackableProperty.Sideboard;
default:
return null; //other zones not represented
}

View File

@@ -0,0 +1,52 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.game.replacement;
import java.util.Map;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
public class ReplaceLearn extends ReplacementEffect {
public ReplaceLearn(Map<String, String> map, Card host, boolean intrinsic) {
super(map, host, intrinsic);
}
/* (non-Javadoc)
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
public boolean canReplace(Map<AbilityKey, Object> runParams) {
if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Affected))) {
return false;
}
return true;
}
/* (non-Javadoc)
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/
@Override
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
}
}

View File

@@ -28,6 +28,7 @@ public enum ReplacementType {
DrawCards(ReplaceDrawCards.class),
GainLife(ReplaceGainLife.class),
GameLoss(ReplaceGameLoss.class),
Learn(ReplaceLearn.class),
Mill(ReplaceMill.class),
Moved(ReplaceMoved.class),
ProduceMana(ReplaceProduceMana.class),

View File

@@ -171,6 +171,7 @@ public enum TrackableProperty {
Graveyard(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
Hand(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
Library(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
Sideboard(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
Mana(TrackableTypes.ManaMapType, FreezeMode.IgnoresFreeze),
IsExtraTurn(TrackableTypes.BooleanType),
ExtraTurnCount(TrackableTypes.IntegerType),

View File

@@ -484,6 +484,7 @@ public final class CMatchUI
case Exile:
case Flashback:
case Command:
case Sideboard:
if (FloatingZone.show(this,player,zone)) {
updatedPlayerZones.add(update);
}

View File

@@ -0,0 +1,7 @@
Name:Academic Dispute
ManaCost:R
Types:Instant
A:SP$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | KW$ HIDDEN CARDNAME blocks each combat if able. | SubAbility$ DBPump | StackDescription$ SpellDescription | SpellDescription$ Target creature blocks this turn if able.
SVar:DBPump:DB$ Pump | Defined$ Targeted | KW$ Reach | OptionQuestion$ Do you want TARGETS to gain reach? | SubAbility$ DBLearn | StackDescription$ SpellDescription | SpellDescription$ You may have it gain reach until end of turn.
SVar:DBLearn:DB$ Learn | SpellDescription$ Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
Oracle:Target creature blocks this turn if able. You may have it gain reach until end of turn.\nLearn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,6 @@
Name:Arcane Subtraction
ManaCost:1 U
Types:Instant
A:SP$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -4 | IsCurse$ True | SubAbility$ DBLearn | SpellDescription$ Target creature gets -4/-0 until end of turn.
SVar:DBLearn:DB$ Learn | SpellDescription$ Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
Oracle:Target creature gets -4/-0 until end of turn.\nLearn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,7 @@
Name:Cram Session
ManaCost:1 BG
Types:Sorcery
A:SP$ GainLife | LifeAmount$ 4 | Defined$ You | SubAbility$ DBLearn | SpellDescription$ You gain 4 life.
SVar:DBLearn:DB$ Learn | SpellDescription$ Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
DeckHas:Ability$LifeGain
Oracle:You gain 4 life.\nLearn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,6 @@
Name:Divide by Zero
ManaCost:2 U
Types:Instant
A:SP$ ChangeZone | ValidTgts$ Permanent.cmcGE1,Card.inZoneStack+cmcGE1 | TgtZone$ Stack,Battlefield | Origin$ Battlefield,Stack | Fizzle$ True | Destination$ Hand | SubAbility$ DBLearn | SpellDescription$ Return target spell or permanent with mana value 1 or greater to its owners hand.
SVar:DBLearn:DB$ Learn | SpellDescription$ Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
Oracle:Return target spell or permanent with mana value 1 or greater to its owners hand.\nLearn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,11 @@
Name:Dream Strix
ManaCost:2 U
Types:Creature Bird Ilusion
PT:2/2
K:Flying
T:Mode$ BecomesTarget | ValidTarget$ Card.Self | SourceType$ Spell | TriggerZones$ Battlefield | Execute$ TrigSac | TriggerDescription$ When CARDNAME becomes the target of a spell, sacrifice it.
SVar:TrigSac:DB$ Sacrifice | ValidCard$ Card.Self
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigLearn | TriggerDescription$ When CARDNAME dies, learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
SVar:TrigLearn:DB$ Learn
DeckHas:Ability$Sacrifice
Oracle:Flying\nWhen Dream Strix becomes the target of a spell, sacrifice it.\nWhen Dream Strix dies, learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,6 @@
Name:Enthusiastic Study
ManaCost:2 R
Types:Instant
A:SP$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ +3 | NumDef$ +1 | KW$ Trample | SubAbility$ DBLearn | SpellDescription$ Target creature gets +3/+1 and gains trample until end of turn.
SVar:DBLearn:DB$ Learn | SpellDescription$ Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
Oracle:Target creature gets +3/+1 and gains trample until end of turn.\nLearn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,9 @@
Name:Eyetwitch
ManaCost:B
Types:Creature Eye Bat
PT:1/1
K:Flying
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigLearn | TriggerDescription$ When CARDNAME dies, learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
SVar:TrigLearn:DB$ Learn
SVar:SacMe:1
Oracle:Flying\nWhen Eyetwitch dies, learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,6 @@
Name:Field Trip
ManaCost:2 G
Types:Sorcery
A:SP$ ChangeZone | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Forest+Basic | ChangeNum$ 1 | SubAbility$ DBLearn | SpellDescription$ Search your library for a basic Forest card, put that card onto the battlefield tapped, then shuffle.
SVar:DBLearn:DB$ Learn | SpellDescription$ Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
Oracle:Search your library for a basic Forest card, put that card onto the battlefield tapped, then shuffle.\nLearn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,10 @@
Name:First Day of Class
ManaCost:1 R
Types:Instant
A:SP$ Effect | Triggers$ CreatureETB | SubAbility$ DBLearn | SpellDescription$ Whenever a creature enters the battlefield under your control this turn, put a +1/+1 counter on it and it gains haste until end of turn.
SVar:CreatureETB:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.YouCtrl | TriggerZones$ Command | Execute$ TrigPutCounter | TriggerDescription$ Whenever a creature enters the battlefield under your control this turn, put a +1/+1 counter on it and it gains haste until end of turn.
SVar:TrigPutCounter:DB$ PutCounter | Defined$ TriggeredCardLKICopy | CounterType$ P1P1 | SubAbility$ DBPump
SVar:DBPump:DB$ Pump | Defined$ TriggeredCard | KW$ Haste
SVar:DBLearn:DB$ Learn | SpellDescription$ Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
DeckHas:Ability$Counters
Oracle:Whenever a creature enters the battlefield under your control this turn, put a +1/+1 counter on it and it gains haste until end of turn.\nLearn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,8 @@
Name:Gnarled Professor
ManaCost:2 G G
Types:Creature Treefolk Druid
PT:5/4
K:Trample
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigLearn | TriggerDescription$ When CARDNAME enters the battlefield, learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
SVar:TrigLearn:DB$ Learn
Oracle:Trample\nWhen Gnarled Professor enters the battlefield, learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,7 @@
Name:Guiding Voice
ManaCost:W
Types:Sorcery
A:SP$ PutCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBLearn | SpellDescription$ Put a +1/+1 counter on target creature.
SVar:DBLearn:DB$ Learn | SpellDescription$ Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
DeckHas:Ability$Counters
Oracle:Put a +1/+1 counter on target creature.\nLearn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,7 @@
Name:Hunt for Specimens
ManaCost:1 B
Types:Sorcery
A:SP$ Token | TokenScript$ bg_1_1_pest_lifegain | SubAbility$ DBLearn | SpellDescription$ Create a 1/1 black and green Pest creature token with "When this creature dies, you gain 1 life."
SVar:DBLearn:DB$ Learn | SpellDescription$ Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
DeckHas:Ability$Token & Ability$LifeGain
Oracle:Create a 1/1 black and green Pest creature token with "When this creature dies, you gain 1 life."\nLearn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,6 @@
Name:Igneous Inspiration
ManaCost:2 R
Types:Sorcery
A:SP$ DealDamage | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 3 | SubAbility$ DBLearn | SpellDescription$ CARDNAME deals 3 damage to any target.
SVar:DBLearn:DB$ Learn | SpellDescription$ Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
Oracle:Igneous Inspiration deals 3 damage to any target.\nLearn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,9 @@
Name:Overgrown Arch
ManaCost:1 G
Types:Creature Plant Wall
PT:0/4
K:Defender
A:AB$ GainLife | Cost$ T | LifeAmount$ 1 | SpellDescription$ You gain 1 life.
A:AB$ Learn | Cost$ 2 Sac<1/CARDNAME> | SpellDescription$ Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
DeckHas:Ability$LifeGain & Ability$Sacrifice
Oracle:Defender\n{T}: You gain 1 life.\n{2}, Sacrifice Overgrown Arch: Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,8 @@
Name:Poet's Quill
ManaCost:1 B
Types:Artifact — Equipment
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigLearn | TriggerDescription$ When CARDNAME enters the battlefield, learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
SVar:TrigLearn:DB$ Learn
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 1 | AddToughness$ 1 | AddKeyword$ Lifelink | Description$ Equipped creature gets +1/+1 and has lifelink.
K:Equip:1 B
Oracle:When Poet's Quill enters the battlefield, learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)\nEquipped creature gets +1/+1 and has lifelink.\nEquip {1}{B}

View File

@@ -0,0 +1,6 @@
Name:Pop Quiz
ManaCost:2 U
Types:Instant
A:SP$ Draw | Cost$ 2 U | Defined$ You | NumCards$ 1 | SubAbility$ DBLearn | SpellDescription$ Draw a card.
SVar:DBLearn:DB$ Learn | SpellDescription$ Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
Oracle:Draw a card.\nLearn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,7 @@
Name:Professor of Symbology
ManaCost:1 W
Types:Creature Kor Cleric
PT:2/1
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigLearn | TriggerDescription$ When CARDNAME enters the battlefield, Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
SVar:TrigLearn:DB$ Learn
Oracle:When Professor of Symbology enters the battlefield, learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,11 @@
Name:Retriever Phoenix
ManaCost:3 R
Types:Creature Phoenix
PT:2/2
K:Flying
K:Haste
T:Mode$ ChangesZone | ValidCard$ Card.wasCast+Self | Destination$ Battlefield | Execute$ TrigLearn | TriggerDescription$ When CARDNAME enters the battlefield, if you cast it, learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
R:Event$ Learn | ActiveZones$ Graveyard | ValidPlayer$ You | Optional$ True | ReplaceWith$ Return | IsPresent$ Card.Self | Description$ As long as CARDNAME is in your graveyard, if you would learn, you may instead return CARDNAME to the battlefield.
SVar:Return:DB$ ChangeZone | Defined$ Self | Origin$ Graveyard | Destination$ Battlefield
DeckHas:Ability$Graveyard
Oracle:Flying, haste\nWhen Retriever Phoenix enters the battlefield, if you cast it, learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)\nAs long as Retriever Phoenix is in your graveyard, if you would learn, you may instead return Retriever Phoenix to the battlefield.

View File

@@ -0,0 +1,7 @@
Name:Rise of Extus
ManaCost:4 W/B W/B
Types:Sorcery
A:SP$ ChangeZone | ValidTgts$ Creature | TgtPrompt$ Select target creature | Origin$ Battlefield | Destination$ Exile | SubAbility$ DBExile | SpellDescription$ Exile target creature.
SVar:DBExile:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | TargetMin$ 0 | ValidTgts$ Instant,Sorcery | TgtPrompt$ Select up to one target instant or sorcery card from a graveyard | SubAbility$ DBLearn | SpellDescription$ Exile up to one target instant or sorcery card from a graveyard.
SVar:DBLearn:DB$ Learn | SpellDescription$ Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
Oracle:Exile target creature. Exile up to one target instant or sorcery card from a graveyard.\nLearn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -0,0 +1,10 @@
Name:Sparring Regimen
ManaCost:2 W
Types:Enchantment
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigLearn | TriggerDescription$ When CARDNAME enters the battlefield, learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
SVar:TrigLearn:DB$ Learn
T:Mode$ AttackersDeclared | AttackingPlayer$ You | Execute$ TrigPutCounter | TriggerZones$ Battlefield | TriggerDescription$ Whenever you attack, put a +1/+1 counter on target attacking creature and untap it.
SVar:TrigPutCounter:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ 1 | ValidTgts$ Creature.attacking | TgtPrompt$ Select target attacking creature | SubAbility$ DBUntap
SVar:DBUntap:DB$ Untap | Defined$ Targeted
DeckHas:Ability$Counters
Oracle:When Sparring Regimen enters the battlefield, learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)\nWhenever you attack, put a +1/+1 counter on target attacking creature and untap it.

View File

@@ -0,0 +1,6 @@
Name:Study Break
ManaCost:1 W
Types:Instant
A:SP$ Tap | Cost$ 1 W | TargetMin$ 0 | TargetMax$ 2 | TgtPrompt$ Choose up to two target creatures | ValidTgts$ Creature | SpellDescription$ Tap up to two target creatures. | SubAbility$ DBLearn
SVar:DBLearn:DB$ Learn | SpellDescription$ Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)
Oracle:Tap up to two target creatures.\nLearn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)

View File

@@ -476,8 +476,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
final boolean useUiPointAtCard =
(FModel.getPreferences().getPrefBoolean(FPref.UI_SELECT_FROM_CARD_DISPLAYS) && (!GuiBase.getInterface().isLibgdxPort())) ?
(cz.is(ZoneType.Battlefield) || cz.is(ZoneType.Hand) || cz.is(ZoneType.Library) ||
cz.is(ZoneType.Graveyard) || cz.is(ZoneType.Exile) || cz.is(ZoneType.Flashback) || cz.is(ZoneType.Command)) :
(cz.is(ZoneType.Hand) && cz.getPlayer() == player || cz.is(ZoneType.Battlefield));
cz.is(ZoneType.Graveyard) || cz.is(ZoneType.Exile) || cz.is(ZoneType.Flashback) ||
cz.is(ZoneType.Command) || cz.is(ZoneType.Sideboard)) :
(cz.is(ZoneType.Hand, player) || cz.is(ZoneType.Battlefield));
if (!useUiPointAtCard) {
return false;
}