Merge branch 'master' into 'master'

Basic AI for Gideon Blackblade

See merge request core-developers/forge!1787
This commit is contained in:
Michael Kamensky
2019-06-05 09:10:34 +00:00
3 changed files with 52 additions and 13 deletions

View File

@@ -501,6 +501,49 @@ public class SpecialCardAi {
}
}
// Gideon Blackblade
public static class GideonBlackblade {
public static boolean consider(final Player ai, final SpellAbility sa) {
CardCollectionView otb = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.isTargetableBy(sa));
if (!otb.isEmpty()) {
sa.getTargets().add(ComputerUtilCard.getBestAI(otb));
}
return true;
}
public static SpellAbility chooseSpellAbility(final Player ai, final SpellAbility sa, final List<SpellAbility> spells) {
// TODO: generalize and improve this so that it acts in a more reasonable way and can potentially be used for other cards too
List<SpellAbility> best = Lists.newArrayList();
List<SpellAbility> possible = Lists.newArrayList();
Card tgtCard = sa.getTargetCard();
if (tgtCard != null) {
for (SpellAbility sp : spells) {
if (SpellApiToAi.Converter.get(sp.getApi()).canPlayAIWithSubs(ai, sp)) {
best.add(sp); // these SAs are prioritized since the AI sees a reason to play them now
}
final List<String> keywords = sp.hasParam("KW") ? Arrays.asList(sp.getParam("KW").split(" & "))
: Lists.<String>newArrayList();
for (String kw : keywords) {
if (!tgtCard.hasKeyword(kw)) {
if ("Indestructible".equals(kw) && ai.getOpponents().getCreaturesInPlay().isEmpty()) {
continue; // nothing to damage or kill the creature with
}
possible.add(sp); // these SAs at least don't duplicate a keyword on the card
break;
}
}
}
}
if (!best.isEmpty()) {
return Aggregates.random(best);
} else if (!possible.isEmpty()) {
return Aggregates.random(possible);
} else {
return Aggregates.random(spells); // if worst comes to worst, it's a PW +1 ability, so do at least something
}
}
}
// Guilty Conscience
public static class GuiltyConscience {
public static Card getBestAttachTarget(final Player ai, final SpellAbility sa, final List<Card> list) {

View File

@@ -1,5 +1,6 @@
package forge.ai.ability;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -8,21 +9,12 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import forge.ai.ComputerUtilAbility;
import forge.ai.*;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi;
import forge.ai.SpellApiToAi;
import forge.card.MagicColor;
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.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil;
import forge.game.card.CounterType;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.Cost;
@@ -50,6 +42,8 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
return true;
}
}
} else if ("GideonBlackblade".equals(aiLogic)) {
return SpecialCardAi.GideonBlackblade.consider(ai, sa);
}
return false;
}
@@ -95,7 +89,9 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
return spells.get(0);
} else if ("Random".equals(logic)) {
return Aggregates.random(spells);
} else if ("Phasing".equals(logic)) { // Teferi's Realm : keep aggressive
} else if ("GideonBlackblade".equals(logic)) {
return SpecialCardAi.GideonBlackblade.chooseSpellAbility(player, sa, spells);
} else if ("Phasing".equals(logic)) { // Teferi's Realm : keep aggressive
List<SpellAbility> filtered = Lists.newArrayList(Iterables.filter(spells, new Predicate<SpellAbility>() {
@Override
public boolean apply(final SpellAbility sp) {

View File

@@ -4,7 +4,7 @@ Types:Legendary Planeswalker Gideon
Loyalty:4
S:Mode$ Continuous | Affected$ Card.Self | EffectZone$ Battlefield | Condition$ PlayerTurn | SetPower$ 4 | SetToughness$ 4 | AddType$ Creature & Human & Soldier | AddKeyword$ Indestructible | Description$ As long as it's your turn, CARDNAME is a 4/4 Human Soldier creature with indestructible that's still a planeswalker.
R:Event$ DamageDone | Prevent$ True | ValidTarget$ Card.Self | PlayerTurn$ True | Description$ Prevent all damage that would be dealt to CARDNAME during your turn.
A:AB$ GenericChoice | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | TargetMin$ 0 | TargetMax$ 1 | ValidTgts$ Creature.YouCtrl+Other | TgtPrompt$ Select to one target creature you control | Choices$ DBVigilance,DBLifelink,DBIndestructible | Defined$ You | ConditionDefined$ Targeted | ConditionPresent$ Card | ConditionCompare$ GE1 | SpellDescription$ Up to one other target creature you control gains your choice of vigilance, lifelink, or indestructible until end of turn. | StackDescription$ SpellDescription
A:AB$ GenericChoice | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | TargetMin$ 0 | TargetMax$ 1 | ValidTgts$ Creature.YouCtrl+Other | TgtPrompt$ Select up to one target creature you control | Choices$ DBVigilance,DBLifelink,DBIndestructible | Defined$ You | ConditionDefined$ Targeted | ConditionPresent$ Card | ConditionCompare$ GE1 | AILogic$ GideonBlackblade | SpellDescription$ Up to one other target creature you control gains your choice of vigilance, lifelink, or indestructible until end of turn. | StackDescription$ SpellDescription
SVar:DBVigilance:DB$ Pump | Defined$ Targeted | KW$ Vigilance | SpellDescription$ Targeted creature gains Vigilance until end of turn.
SVar:DBLifelink:DB$ Pump | Defined$ Targeted | KW$ Lifelink | SpellDescription$ Targeted creature gains Lifelink until end of turn.
SVar:DBIndestructible:DB$ Pump | Defined$ Targeted | KW$ Indestructible | SpellDescription$ Targeted creature gains Indestructible until end of turn.