Basic AI for Gale's Redirection, Consecrate // Consume, Serra's Emissary (#3376)

* - Basic AI for Gale's Redirection.

* - Clean up.

* - Add resetTargets.

* - Minor style tweak.

* - Improve Consecrate // Consume implementation, enable AI support.

* - Improve Serra's Emissary AI support.
This commit is contained in:
Agetian
2023-07-02 06:50:26 +03:00
committed by GitHub
parent 96c88382dc
commit 7c2e3d2a47
6 changed files with 51 additions and 9 deletions

View File

@@ -2424,6 +2424,18 @@ public class ComputerUtil {
}
}
}
} else if (logic.equals("ProtectionFromType")) {
// TODO: protection vs. damage-dealing and milling instants/sorceries in low creature decks and the like?
// Maybe non-creature artifacts in certain cases?
List<String> choices = ImmutableList.of("Creature", "Planeswalker"); // types that make sense to get protected against
CardCollection evalList = new CardCollection();
evalList.addAll(ai.getOpponents().getCardsIn(ZoneType.Battlefield));
chosen = ComputerUtilCard.getMostProminentCardType(evalList, choices);
if (StringUtils.isEmpty(chosen)) {
chosen = "Creature"; // if in doubt, choose Creature, I guess
}
}
else {
// Are we picking a type to reduce costs for that type?

View File

@@ -28,6 +28,7 @@ import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.TargetRestrictions;
import forge.game.staticability.StaticAbilityMustTarget;
import forge.game.zone.ZoneType;
@@ -116,6 +117,8 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (aiLogic != null) {
if (aiLogic.equals("Always")) {
return true;
} else if (aiLogic.startsWith("ExileSpell")) {
return doExileSpellLogic(aiPlayer, sa);
} else if (aiLogic.startsWith("SacAndUpgrade")) { // Birthing Pod, Natural Order, etc.
return doSacAndUpgradeLogic(aiPlayer, sa);
} else if (aiLogic.startsWith("SacAndRetFromGrave")) { // Recurring Nightmare, etc.
@@ -2075,6 +2078,36 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
}
private boolean doExileSpellLogic(final Player aiPlayer, final SpellAbility sa) {
String aiLogic = sa.getParamOrDefault("AILogic", "");
SpellAbilityStackInstance top = aiPlayer.getGame().getStack().peek();
List<ApiType> dangerousApi = Arrays.asList(ApiType.DealDamage, ApiType.DamageAll, ApiType.Destroy, ApiType.DestroyAll, ApiType.Sacrifice, ApiType.SacrificeAll);
int manaCost = 0;
int minCost = 0;
if (aiLogic.contains(".")) {
minCost = Integer.parseInt(aiLogic.substring(aiLogic.indexOf(".") + 1));
}
if (top != null) {
SpellAbility topSA = top.getSpellAbility(false);
if (topSA != null) {
if (topSA.getPayCosts().hasManaCost()) {
manaCost = topSA.getPayCosts().getTotalMana().getCMC();
}
if ((manaCost >= minCost || dangerousApi.contains(topSA.getApi()))
&& topSA.getActivatingPlayer().isOpponentOf(aiPlayer)
&& sa.canTargetSpellAbility(topSA)) {
sa.resetTargets();
sa.getTargets().add(topSA);
return sa.isTargetNumberValid();
}
}
}
return false;
}
private static CardCollection getSafeTargetsIfUnlessCostPaid(Player ai, SpellAbility sa, Iterable<Card> potentialTgts) {
// Determines if the controller of each potential target can negate the ChangeZone effect
// by paying the Unless cost. Returns the list of targets that can be saved that way.

View File

@@ -114,13 +114,14 @@ public class SacrificeAi extends SpellAbilityAi {
}
final String defined = sa.getParamOrDefault("Defined", "You");
final String targeted = sa.getParamOrDefault("ValidTgts", "");
final String valid = sa.getParamOrDefault("SacValid", "Self");
if (valid.equals("Self")) {
// Self Sacrifice.
} else if (defined.equals("Player")
} else if (defined.equals("Player") || targeted.equals("Player") || targeted.equals("Opponent")
|| ((defined.equals("Player.Opponent") || defined.equals("Opponent")) && !sa.isTrigger())) {
// is either "Defined$ Player.Opponent" or "Defined$ Opponent" obsolete?
// If Sacrifice hits both players:
// Only cast it if Human has the full amount of valid
// Only cast it if AI doesn't have the full amount of Valid

View File

@@ -11,11 +11,8 @@ ALTERNATE
Name:Consume
ManaCost:2 W B
Types:Sorcery
A:SP$ Pump | Cost$ 2 W B | ValidTgts$ Player | IsCurse$ True | RememberTargets$ True | SubAbility$ DBChooseCard | SpellDescription$ Target player sacrifices a creature with the greatest power among creatures they control. You gain life equal to its power.
SVar:DBChooseCard:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Creature.greatestPowerControlledByRemembered | Mandatory$ True | SubAbility$ DBSac
SVar:DBSac:DB$ Sacrifice | Defined$ Player.IsRemembered | SacValid$ Card.ChosenCard | RememberSacrificed$ True | SubAbility$ DBGainLife | SacMessage$ the creature with the highest power
A:SP$ Sacrifice | Cost$ 2 W B | ValidTgts$ Player | SacValid$ Creature.greatestPowerControlledByTargered | Mandatory$ True | SubAbility$ DBGainLife | SacMessage$ the creature with the highest power | RememberSacrificed$ True | SpellDescription$ Target player sacrifices a creature with the greatest power among creatures they control. You gain life equal to its power.
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ X | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:RememberedLKI$CardPower
SVar:SplitNeedsToPlay:Creature.OppCtrl
Oracle:Target player sacrifices a creature with the greatest power among creatures they control. You gain life equal to its power.

View File

@@ -1,7 +1,7 @@
Name:Gale's Redirection
ManaCost:3 U U
Types:Instant
A:SP$ ChangeZone | ValidTgts$ Card | TargetType$ Spell | TgtZone$ Stack | Origin$ Stack | Fizzle$ True | Destination$ Exile | TgtPrompt$ Choose target spell to exile | RememberChanged$ True | SubAbility$ DBRoll | SpellDescription$ Exile target spell.
A:SP$ ChangeZone | ValidTgts$ Card | TargetType$ Spell | TgtZone$ Stack | Origin$ Stack | Fizzle$ True | Destination$ Exile | AILogic$ ExileSpell.3 | TgtPrompt$ Choose target spell to exile | RememberChanged$ True | SubAbility$ DBRoll | SpellDescription$ Exile target spell.
SVar:DBRoll:DB$ RollDice | Sides$ 20 | Modifier$ Y | ResultSubAbilities$ 1-14:DBMayPlay,Else:DBMayPlayWithoutCost | StackDescription$ SpellDescription | SpellDescription$ Roll a d20 and add that spell's mana value.
SVar:DBMayPlay:DB$ Effect | StaticAbilities$ STPlay | RememberObjects$ Remembered | Duration$ Permanent | ExileOnMoved$ Exile | SubAbility$ DBCleanup | SpellDescription$ 1—14 VERT You may cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any color to cast it.
SVar:DBMayPlayWithoutCost:DB$ Effect | StaticAbilities$ STPlayWithoutCost | RememberObjects$ Remembered | Duration$ Permanent | ExileOnMoved$ Exile | SubAbility$ DBCleanup | SpellDescription$ 15+ VERT You may cast that card without paying its mana cost for as long as it remains exiled.
@@ -9,5 +9,4 @@ SVar:STPlay:Mode$ Continuous | MayPlay$ True | MayPlayIgnoreColor$ True | Effect
SVar:STPlayWithoutCost:Mode$ Continuous | MayPlay$ True | MayPlayWithoutManaCost$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonLand | AffectedZone$ Exile | Description$ You may cast that card without paying its mana cost for as long as it remains exiled.
SVar:Y:SpellTargeted$CardManaCostLKI
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
AI:RemoveDeck:All
Oracle:Exile target spell, then roll a d20 and add that spell's mana value.\n1-14 | You may cast the exiled card for as long as it remains exiled, and you may spend mana as though it were mana of any color to cast that spell.\n15+ | You may cast the exiled card without paying its mana cost for as long as it remains exiled.

View File

@@ -4,7 +4,7 @@ Types:Creature Angel
PT:7/7
K:Flying
K:ETBReplacement:Other:ChooseCT
SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Card | AILogic$ MostProminentOppControls | SpellDescription$ As CARDNAME enters the battlefield, choose a card type.
SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Card | AILogic$ ProtectionFromType | SpellDescription$ As CARDNAME enters the battlefield, choose a card type.
S:Mode$ Continuous | Affected$ You,Creature.YouCtrl | AddKeyword$ Protection from ChosenType | Description$ You and creatures you control have protection from the chosen card type.
SVar:PlayMain1:TRUE
Oracle:Flying\nAs Serra's Emissary enters the battlefield, choose a card type.\nYou and creatures you control have protection from the chosen card type.