Commit f2dddd55 authored by swordshine's avatar swordshine

Merge branch 'ai-blink-reload-pw' into 'master'

AI logic to blink-reload a planeswalker using Teferi's Time Twist.

See merge request !1680
parents cdeb944a c5e45187
......@@ -129,7 +129,10 @@ public enum AiProps { /** */
FLASH_USE_BUFF_AURAS_AS_COMBAT_TRICKS("true"),
FLASH_BUFF_AURA_CHANCE_TO_CAST_EARLY("1"),
FLASH_BUFF_AURA_CHANCE_CAST_AT_EOT("5"),
FLASH_BUFF_AURA_CHANCE_TO_RESPOND_TO_STACK("100"); /** */
FLASH_BUFF_AURA_CHANCE_TO_RESPOND_TO_STACK("100"),
BLINK_RELOAD_PLANESWALKER_CHANCE("30"), /** */
BLINK_RELOAD_PLANESWALKER_MAX_LOYALTY("2"), /** */
BLINK_RELOAD_PLANESWALKER_LOYALTY_DIFF("2"); /** */
// Experimental features, must be promoted or removed after extensive testing and, ideally, defaulting
// <-- There are no experimental options here -->
......
......@@ -26,6 +26,7 @@ import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
......@@ -677,7 +678,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
// only use blink or bounce effects
if (!(destination.equals(ZoneType.Exile)
&& (subApi == ApiType.DelayedTrigger || subApi == ApiType.ChangeZone || "DelayedBounce".equals(sa.getParam("AILogic"))))
&& (subApi == ApiType.DelayedTrigger || subApi == ApiType.ChangeZone || "DelayedBlink".equals(sa.getParam("AILogic"))))
&& !destination.equals(ZoneType.Hand)) {
return false;
}
......@@ -937,7 +938,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
// if it's blink or bounce, try to save my about to die stuff
final boolean blink = (destination.equals(ZoneType.Exile) && (subApi == ApiType.DelayedTrigger
|| "DelayedBounce".equals(sa.getParam("AILogic")) || (subApi == ApiType.ChangeZone && subAffected.equals("Remembered"))));
|| "DelayedBlink".equals(sa.getParam("AILogic")) || (subApi == ApiType.ChangeZone && subAffected.equals("Remembered"))));
if ((destination.equals(ZoneType.Hand) || blink) && (tgt.getMinTargets(sa.getHostCard(), sa) <= 1)) {
// save my about to die stuff
Card tobounce = canBouncePermanent(ai, sa, list);
......@@ -1231,6 +1232,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
// filter out untargetables
CardCollectionView aiPermanents = CardLists
.filterControlledBy(list, ai);
CardCollection aiPlaneswalkers = CardLists.filter(aiPermanents, Presets.PLANESWALKERS);
// Felidar Guardian + Saheeli Rai combo support
if (sa.getHostCard().getName().equals("Felidar Guardian")) {
......@@ -1274,6 +1276,33 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
}
}
// Reload planeswalkers
else if (!aiPlaneswalkers.isEmpty() && (sa.getHostCard().isSorcery() || !game.getPhaseHandler().isPlayerTurn(ai))) {
int maxLoyaltyToConsider = 2;
int loyaltyDiff = 2;
int chance = 30;
if (ai.getController().isAI()) {
AiController aic = ((PlayerControllerAi) ai.getController()).getAi();
maxLoyaltyToConsider = aic.getIntProperty(AiProps.BLINK_RELOAD_PLANESWALKER_MAX_LOYALTY);
loyaltyDiff = aic.getIntProperty(AiProps.BLINK_RELOAD_PLANESWALKER_LOYALTY_DIFF);
chance = aic.getIntProperty(AiProps.BLINK_RELOAD_PLANESWALKER_CHANCE);
}
if (MyRandom.percentTrue(chance)) {
Collections.sort(aiPlaneswalkers, new Comparator<Card>() {
@Override
public int compare(final Card a, final Card b) {
return a.getCounters(CounterType.LOYALTY) - b.getCounters(CounterType.LOYALTY);
}
});
for (Card pw : aiPlaneswalkers) {
int curLoyalty = pw.getCounters(CounterType.LOYALTY);
int freshLoyalty = pw.getCurrentState().getBaseLoyalty();
if (freshLoyalty - curLoyalty >= loyaltyDiff && curLoyalty <= maxLoyaltyToConsider) {
return pw;
}
}
}
}
return null;
}
......
......@@ -252,6 +252,14 @@ BOUNCE_ALL_ELSEWHERE_CREAT_EVAL_DIFF=200
BOUNCE_ALL_TO_HAND_NONCREAT_EVAL_DIFF=3
BOUNCE_ALL_ELSEWHERE_NONCREAT_EVAL_DIFF=3
# Use a blink spell to reload a planeswalker's loyalty (e.g. Teferi's Time Twist)
# A chance (per check) to activate this ability
BLINK_RELOAD_PLANESWALKER_CHANCE=15
# Maximum loyalty at which the planeswalker needs to be in order to activate the blink-reload
BLINK_RELOAD_PLANESWALKER_MAX_LOYALTY=2
# The difference between maximum loyalty and base loyalty of the planeswalker in order to consider blink-reloading it
BLINK_RELOAD_PLANESWALKER_LOYALTY_DIFF=2
# If enabled, the AI will try to pair up cards to present to the opponent so that a specific card may be picked,
# it'll also try to grab Accumulated Knowledge and Take Inventory more actively, as well as interact with the Trix
# combo deck more appropriately. In Reanimator decks, this logic will make the AI pick the fattest threats in the
......
......@@ -253,6 +253,14 @@ BOUNCE_ALL_ELSEWHERE_CREAT_EVAL_DIFF=200
BOUNCE_ALL_TO_HAND_NONCREAT_EVAL_DIFF=3
BOUNCE_ALL_ELSEWHERE_NONCREAT_EVAL_DIFF=3
# Use a blink spell to reload a planeswalker's loyalty (e.g. Teferi's Time Twist)
# A chance (per check) to activate this ability
BLINK_RELOAD_PLANESWALKER_CHANCE=30
# Maximum loyalty at which the planeswalker needs to be in order to activate the blink-reload
BLINK_RELOAD_PLANESWALKER_MAX_LOYALTY=2
# The difference between maximum loyalty and base loyalty of the planeswalker in order to consider blink-reloading it
BLINK_RELOAD_PLANESWALKER_LOYALTY_DIFF=2
# If enabled, the AI will try to pair up cards to present to the opponent so that a specific card may be picked,
# it'll also try to grab Accumulated Knowledge and Take Inventory more actively, as well as interact with the Trix
# combo deck more appropriately. In Reanimator decks, this logic will make the AI pick the fattest threats in the
......
......@@ -253,6 +253,14 @@ BOUNCE_ALL_ELSEWHERE_CREAT_EVAL_DIFF=400
BOUNCE_ALL_TO_HAND_NONCREAT_EVAL_DIFF=5
BOUNCE_ALL_ELSEWHERE_NONCREAT_EVAL_DIFF=5
# Use a blink spell to reload a planeswalker's loyalty (e.g. Teferi's Time Twist)
# A chance (per check) to activate this ability
BLINK_RELOAD_PLANESWALKER_CHANCE=70
# Maximum loyalty at which the planeswalker needs to be in order to activate the blink-reload
BLINK_RELOAD_PLANESWALKER_MAX_LOYALTY=2
# The difference between maximum loyalty and base loyalty of the planeswalker in order to consider blink-reloading it
BLINK_RELOAD_PLANESWALKER_LOYALTY_DIFF=1
# If enabled, the AI will try to pair up cards to present to the opponent so that a specific card may be picked,
# it'll also try to grab Accumulated Knowledge and Take Inventory more actively, as well as interact with the Trix
# combo deck more appropriately. In Reanimator decks, this logic will make the AI pick the fattest threats in the
......
......@@ -253,6 +253,14 @@ BOUNCE_ALL_ELSEWHERE_CREAT_EVAL_DIFF=200
BOUNCE_ALL_TO_HAND_NONCREAT_EVAL_DIFF=3
BOUNCE_ALL_ELSEWHERE_NONCREAT_EVAL_DIFF=3
# Use a blink spell to reload a planeswalker's loyalty (e.g. Teferi's Time Twist)
# A chance (per check) to activate this ability
BLINK_RELOAD_PLANESWALKER_CHANCE=60
# Maximum loyalty at which the planeswalker needs to be in order to activate the blink-reload
BLINK_RELOAD_PLANESWALKER_MAX_LOYALTY=2
# The difference between maximum loyalty and base loyalty of the planeswalker in order to consider blink-reloading it
BLINK_RELOAD_PLANESWALKER_LOYALTY_DIFF=1
# If enabled, the AI will try to pair up cards to present to the opponent so that a specific card may be picked,
# it'll also try to grab Accumulated Knowledge and Take Inventory more actively, as well as interact with the Trix
# combo deck more appropriately. In Reanimator decks, this logic will make the AI pick the fattest threats in the
......
Name:Teferi's Time Twist
ManaCost:1 U
Types:Instant
A:SP$ ChangeZone | Cost$ 1 U | ValidTgts$ Permanent.YouCtrl | TgtPrompt$ Select target permanent you control | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | AILogic$ DelayedBounce | SubAbility$ DBAnimate | SpellDescription$ Exile target permanent you control. Return that card to the battlefield under its owner’s control at the beginning of the next end step. If it enters the battlefield as a creature, it enters with an additional +1/+1 counter on it.
A:SP$ ChangeZone | Cost$ 1 U | ValidTgts$ Permanent.YouCtrl | TgtPrompt$ Select target permanent you control | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | AILogic$ DelayedBlink | SubAbility$ DBAnimate | SpellDescription$ Exile target permanent you control. Return that card to the battlefield under its owner’s control at the beginning of the next end step. If it enters the battlefield as a creature, it enters with an additional +1/+1 counter on it.
SVar:DBAnimate:DB$ Animate | Defined$ Remembered | Keywords$ etbCounter:P1P1:1:ValidCard$ Creature.IsRemembered | RememberObjects$ Remembered | SubAbility$ DelTrig | AILogic$ Always
SVar:DelTrig:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigBounce | RememberObjects$ Remembered | AILogic$ Always | TriggerDescription$ Return that card to the battlefield under its owner’s control at the beginning of the next end step. If it enters the battlefield as a creature, it enters with an additional +1/+1 counter on it.
SVar:TrigBounce:DB$ ChangeZone | Origin$ Exile | Destination$ Battlefield | Defined$ DelayTriggerRemembered
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment