mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 03:08:02 +00:00
Various improvements to AI-related logic (Canopy lands, Ugin's Labyrinth, Zuran Orb, Pyrite Spellbomb, Eladamri) (#6418)
* - Improve AI for Canopy lands. - Improve AI for Ugin's Labyrinth. * - Pyrite Spellbomb: also don't sac immediately. * - Improve AI for Eladamri, Korvecdal * - Improve AI decision for Zuran Orb. * - Cleaner implementation for Eladamri AI - More generic implementation for SacToDraw AI that doesn't need a logic parameter * - Fix imports * - Cleaner implementation for Eladamri AI * - Suggested code tweak
This commit is contained in:
@@ -160,6 +160,9 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
return SpecialCardAi.MazesEnd.consider(aiPlayer, sa);
|
||||
} else if (aiLogic.equals("Pongify")) {
|
||||
return sa.isTargetNumberValid(); // Pre-targeted in checkAiLogic
|
||||
} else if (aiLogic.equals("ReturnCastable")) {
|
||||
return !sa.getHostCard().getExiledCards().isEmpty()
|
||||
&& ComputerUtilMana.canPayManaCost(sa.getHostCard().getExiledCards().getFirst().getFirstSpellAbility(), aiPlayer, 0, false);
|
||||
}
|
||||
}
|
||||
if (sa.isHidden()) {
|
||||
|
||||
@@ -1,25 +1,12 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.ai.AiAttackController;
|
||||
import forge.ai.ComputerUtilAbility;
|
||||
import forge.ai.ComputerUtilCard;
|
||||
import forge.ai.ComputerUtilCombat;
|
||||
import forge.ai.SpellAbilityAi;
|
||||
import com.google.common.collect.Lists;
|
||||
import forge.ai.*;
|
||||
import forge.game.Game;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CardPredicates;
|
||||
import forge.game.card.*;
|
||||
import forge.game.card.CardPredicates.Presets;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.keyword.Keyword;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
@@ -30,6 +17,10 @@ import forge.game.spellability.SpellAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Aggregates;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ChooseCardAi extends SpellAbilityAi {
|
||||
|
||||
/**
|
||||
@@ -58,11 +49,15 @@ public class ChooseCardAi extends SpellAbilityAi {
|
||||
protected boolean checkAiLogic(final Player ai, final SpellAbility sa, final String aiLogic) {
|
||||
final Card host = sa.getHostCard();
|
||||
final Game game = ai.getGame();
|
||||
ZoneType choiceZone = ZoneType.Battlefield;
|
||||
|
||||
List<ZoneType> choiceZone;
|
||||
if (sa.hasParam("ChoiceZone")) {
|
||||
choiceZone = ZoneType.smartValueOf(sa.getParam("ChoiceZone"));
|
||||
choiceZone = ZoneType.listValueOf(sa.getParam("ChoiceZone"));
|
||||
} else {
|
||||
choiceZone = Lists.newArrayList(ZoneType.Battlefield);
|
||||
}
|
||||
CardCollectionView choices = game.getCardsIn(choiceZone);
|
||||
|
||||
if (sa.hasParam("Choices")) {
|
||||
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host, sa);
|
||||
}
|
||||
@@ -129,6 +124,13 @@ public class ChooseCardAi extends SpellAbilityAi {
|
||||
ownChoices = CardLists.filter(choices, CardPredicates.isControlledByAnyOf(ai.getAllies()));
|
||||
}
|
||||
return !ownChoices.isEmpty();
|
||||
} else if (aiLogic.equals("GoodCreature")) {
|
||||
for (Card choice : choices) {
|
||||
if (choice.isCreature() && ComputerUtilCard.evaluateCreature(choice) >= 250) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -81,6 +81,13 @@ public class DrawAi extends SpellAbilityAi {
|
||||
if (!canLoot(ai, sa)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ComputerUtilCost.isSacrificeSelfCost(sa.getPayCosts())) {
|
||||
// Canopy lands and other cards that sacrifice themselves to draw cards
|
||||
return ai.getCardsIn(ZoneType.Hand).isEmpty()
|
||||
|| (sa.getHostCard().isLand() && ai.getLandsInPlay().size() >= 5); // TODO: make this configurable in the AI profile
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,9 @@ public class LifeGainAi extends SpellAbilityAi {
|
||||
|
||||
if (!lifeCritical) {
|
||||
// return super.willPayCosts(ai, sa, cost, source);
|
||||
if ("CriticalOnly".equals(sa.getParam("AILogic"))) {
|
||||
return false;
|
||||
}
|
||||
if (!ComputerUtilCost.checkSacrificeCost(ai, cost, source, sa, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ Types:Legendary Creature Elf Warrior
|
||||
PT:3/3
|
||||
S:Mode$ Continuous | Affected$ Card.TopLibrary+YouCtrl | AffectedZone$ Library | MayLookAt$ You | Description$ You may look at the top card of your library any time.
|
||||
S:Mode$ Continuous | Affected$ Creature.TopLibrary+YouCtrl+nonLand | AffectedZone$ Library | MayPlay$ True | Description$ You may cast creature spells from the top of your library.
|
||||
A:AB$ ChooseCard | Cost$ G T tapXType<2/Creature> | ChoiceZone$ Hand,Library | PlayerTurn$ True | Reveal$ True | Choices$ Card.TopLibrary+YouOwn,Card.YouOwn+inZoneHand | SubAbility$ DBChangeZone | ChoiceTitle$ Reveal a card from your hand or the top of your library | SpellDescription$ Reveal a card from your hand or the top of your library. If you reveal a creature card this way, put it onto the battlefield. Activate only during your turn.
|
||||
A:AB$ ChooseCard | Cost$ G T tapXType<2/Creature> | ChoiceZone$ Hand,Library | PlayerTurn$ True | Reveal$ True | Choices$ Card.TopLibrary+YouOwn,Card.YouOwn+inZoneHand | SubAbility$ DBChangeZone | ChoiceTitle$ Reveal a card from your hand or the top of your library | AILogic$ GoodCreature | SpellDescription$ Reveal a card from your hand or the top of your library. If you reveal a creature card this way, put it onto the battlefield. Activate only during your turn.
|
||||
SVar:DBChangeZone:DB$ ChangeZone | Defined$ ChosenCard | Origin$ Library,Hand | ConditionDefined$ ChosenCard | ConditionPresent$ Creature | Destination$ Battlefield | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True
|
||||
Oracle:You may look at the top of your library at any time.\nYou may cast creature spells from the top of your library.\n{G}, {T}, Tap two untapped creatures you control: Reveal a card from your hand or the top of your library. If you reveal a creature card this way, put it onto the battlefield. Activate only during your turn.
|
||||
|
||||
@@ -4,7 +4,7 @@ Types:Land
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | OptionalDecider$ You | Execute$ TrigExile | TriggerDescription$ Imprint — When CARDNAME enters, you may exile a colorless card with mana value 7 or greater from your hand.
|
||||
SVar:TrigExile:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | ChangeType$ Card.Colorless+cmcGE7 | ChangeNum$ 1
|
||||
A:AB$ Mana | Cost$ T | Produced$ C | Amount$ X | SpellDescription$ Add {C}. If a card is exiled with CARDNAME, add {C}{C} instead.
|
||||
A:AB$ ChangeZone | Cost$ T | Defined$ ExiledWith | Origin$ Exile | Destination$ Hand | SpellDescription$ Return the exiled card to its owner's hand.
|
||||
A:AB$ ChangeZone | Cost$ T | Defined$ ExiledWith | Origin$ Exile | Destination$ Hand | AILogic$ ReturnCastable | SpellDescription$ Return the exiled card to its owner's hand.
|
||||
SVar:X:Count$Compare Y GE1.2.1
|
||||
SVar:Y:Count$ValidExile Card.ExiledWithSource
|
||||
Oracle:Imprint — When Ugin's Labyrinth enters, you may exile a colorless card with mana value 7 or greater from your hand.\n{T}: Add {C}. If a card is exiled with Ugin's Labyrinth, add {C}{C} instead.\n{T}: Return the exiled card to its owner's hand.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Name:Zuran Orb
|
||||
ManaCost:0
|
||||
Types:Artifact
|
||||
A:AB$ GainLife | Cost$ Sac<1/Land> | LifeAmount$ 2 | SpellDescription$ You gain 2 life.
|
||||
A:AB$ GainLife | Cost$ Sac<1/Land> | LifeAmount$ 2 | AILogic$ CriticalOnly | SpellDescription$ You gain 2 life.
|
||||
SVar:NonStackingEffect:True
|
||||
Oracle:Sacrifice a land: You gain 2 life.
|
||||
|
||||
Reference in New Issue
Block a user