mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-11 16:26:22 +00:00
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:
@@ -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?
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user