mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 18:28:00 +00:00
Fix AI not targeting triggered Random Charm (#8955)
This commit is contained in:
@@ -377,7 +377,7 @@ public class AiController {
|
||||
|
||||
if (card.isSaga()) {
|
||||
for (final Trigger tr : card.getTriggers()) {
|
||||
if (tr.getMode() != TriggerType.CounterAdded || !tr.isChapter()) {
|
||||
if (!tr.isChapter()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -393,6 +393,7 @@ public class AiController {
|
||||
return false;
|
||||
}
|
||||
|
||||
// usually later chapters make use of an earlier one
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1274,9 +1274,15 @@ public class PlayerControllerAi extends PlayerController {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean prepareSingleSa(final Card host, final SpellAbility sa, boolean isMandatory) {
|
||||
private boolean prepareSingleSa(final Card host, SpellAbility sa, boolean isMandatory) {
|
||||
if (sa.getApi() == ApiType.Charm) {
|
||||
return CharmEffect.makeChoices(sa);
|
||||
if (!CharmEffect.makeChoices(sa)) {
|
||||
return false;
|
||||
}
|
||||
if (!sa.hasParam("Random")) {
|
||||
return true;
|
||||
}
|
||||
sa = sa.getSubAbility();
|
||||
}
|
||||
if (sa.hasParam("TargetingPlayer")) {
|
||||
Player targetingPlayer = AbilityUtils.getDefinedPlayers(host, sa.getParam("TargetingPlayer"), sa).get(0);
|
||||
|
||||
@@ -634,6 +634,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
// not urgent, get the largest creature possible
|
||||
// TODO checkETBEffects
|
||||
return ComputerUtilCard.getBestCreatureAI(list);
|
||||
}
|
||||
|
||||
@@ -1546,10 +1547,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
if (fetchList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
String type = sa.getParam("ChangeType");
|
||||
if (type == null) {
|
||||
type = "Card";
|
||||
}
|
||||
String type = sa.getParamOrDefault("ChangeType", "");
|
||||
|
||||
Card c = null;
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
|
||||
@@ -94,18 +94,21 @@ public class CharmAi extends SpellAbilityAi {
|
||||
private List<AbilitySub> chooseOptionsAi(SpellAbility sa, List<AbilitySub> choices, final Player ai, boolean isTrigger, int num, int min) {
|
||||
List<AbilitySub> chosenList = Lists.newArrayList();
|
||||
AiController aic = ((PlayerControllerAi) ai.getController()).getAi();
|
||||
boolean allowRepeat = sa.hasParam("CanRepeatModes"); // FIXME: unused for now, the AI doesn't know how to effectively handle repeated choices
|
||||
// TODO unused for now, the AI doesn't know how to effectively handle repeated choices
|
||||
boolean allowRepeat = sa.hasParam("CanRepeatModes");
|
||||
|
||||
// Pawprint
|
||||
final int pawprintLimit = sa.hasParam("Pawprint") ? AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("Pawprint"), sa) : 0;
|
||||
if (pawprintLimit > 0) {
|
||||
Collections.reverse(choices); // try to pay for the more expensive subs first
|
||||
// try to pay for the more expensive subs first
|
||||
Collections.reverse(choices);
|
||||
}
|
||||
int pawprintAmount = 0;
|
||||
|
||||
// First pass using standard canPlayAi() for good choices
|
||||
for (AbilitySub sub : choices) {
|
||||
sub.setActivatingPlayer(ai);
|
||||
// TODO refactor to obtain the AiAbilityDecision instead, then we can check all to sort by value
|
||||
if (AiPlayDecision.WillPlay == aic.canPlaySa(sub)) {
|
||||
if (pawprintLimit > 0) {
|
||||
int curPawprintAmount = AbilityUtils.calculateAmount(sub.getHostCard(), sub.getParamOrDefault("Pawprint", "0"), sub);
|
||||
@@ -116,7 +119,8 @@ public class CharmAi extends SpellAbilityAi {
|
||||
}
|
||||
chosenList.add(sub);
|
||||
if (chosenList.size() == num) {
|
||||
return chosenList; // maximum choices reached
|
||||
// maximum choices reached
|
||||
return chosenList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,7 +149,8 @@ public class CharmAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
if (chosenList.size() < min) {
|
||||
chosenList.clear(); // not enough choices
|
||||
// not enough choices
|
||||
chosenList.clear();
|
||||
}
|
||||
return chosenList;
|
||||
}
|
||||
|
||||
@@ -72,16 +72,14 @@ public class ChooseCardNameAi extends SpellAbilityAi {
|
||||
// 5 percent chance to cast per opposing card with a non mana ability
|
||||
if (MyRandom.getRandom().nextFloat() <= .05 * oppPerms.size()) {
|
||||
return new AiAbilityDecision(100, AiPlayDecision.WillPlay);
|
||||
} else {
|
||||
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
|
||||
}
|
||||
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
|
||||
}
|
||||
|
||||
if (mandatory) {
|
||||
return new AiAbilityDecision(100, AiPlayDecision.WillPlay);
|
||||
} else {
|
||||
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
|
||||
}
|
||||
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.ability.SpellAbilityAi#chooseSingleCard(forge.card.spellability.SpellAbility, java.util.List, boolean)
|
||||
|
||||
@@ -1175,7 +1175,7 @@ public class CountersPutAi extends CountersAi {
|
||||
|
||||
@Override
|
||||
public int chooseNumber(Player player, SpellAbility sa, int min, int max, Map<String, Object> params) {
|
||||
if (sa.hasParam("ReadAhead")) {
|
||||
if (sa.isKeyword(Keyword.READ_AHEAD)) {
|
||||
return 1;
|
||||
}
|
||||
return max;
|
||||
|
||||
@@ -982,6 +982,9 @@ public class AbilityUtils {
|
||||
for (final Card c : getDefinedCards(card, "Targeted", sa)) {
|
||||
players.add(c.getOwner());
|
||||
}
|
||||
for (final SpellAbility s : getDefinedSpellAbilities(card, "Targeted", sa)) {
|
||||
players.add(s.getHostCard().getOwner());
|
||||
}
|
||||
} else if (defined.equals("TargetedAndYou") && sa instanceof SpellAbility) {
|
||||
final SpellAbility saTargeting = ((SpellAbility)sa).getSATargetingPlayer();
|
||||
if (saTargeting != null) {
|
||||
@@ -1118,11 +1121,9 @@ public class AbilityUtils {
|
||||
final String replacingType = defined.substring(8);
|
||||
o = root.getReplacingObject(AbilityKey.fromString(replacingType));
|
||||
}
|
||||
if (o != null) {
|
||||
if (o instanceof Player) {
|
||||
players.add((Player) o);
|
||||
}
|
||||
}
|
||||
} else if (defined.startsWith("Non")) {
|
||||
players.addAll(game.getPlayersInTurnOrder());
|
||||
players.removeAll(getDefinedPlayers(card, defined.substring(3), sa));
|
||||
|
||||
@@ -2496,7 +2496,7 @@ public class CardFactoryUtil {
|
||||
inst.addReplacement(re);
|
||||
} else if (keyword.equals("Read ahead")) {
|
||||
String repeffstr = "Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | Secondary$ True | ReplacementResult$ Updated | Description$ Choose a chapter and start with that many lore counters.";
|
||||
String effStr = "DB$ PutCounter | Defined$ Self | CounterType$ LORE | ETB$ True | UpTo$ True | UpToMin$ 1 | ReadAhead$ True | CounterNum$ FinalChapterNr";
|
||||
String effStr = "DB$ PutCounter | Defined$ Self | CounterType$ LORE | ETB$ True | UpTo$ True | UpToMin$ 1 | CounterNum$ FinalChapterNr";
|
||||
|
||||
SpellAbility saCounter = AbilityFactory.getAbility(effStr, card);
|
||||
saCounter.setSVar("FinalChapterNr", "Count$FinalChapterNr");
|
||||
|
||||
@@ -4,7 +4,7 @@ Types:Artifact
|
||||
K:Flash
|
||||
K:ETBReplacement:Other:DBNameCard
|
||||
SVar:DBNameCard:DB$ NameCard | Defined$ You | SpellDescription$ As CARDNAME enters, choose a card name.
|
||||
S:Mode$ RaiseCost | EffectZone$ Battlefield | ValidCard$ Card.NamedCard | Type$ Spell | Activator$ Player | Amount$ 3 | Description$ Spells with the chosen name cost 3 more to cast.
|
||||
S:Mode$ RaiseCost | EffectZone$ Battlefield | ValidCard$ Card.NamedCard | Type$ Spell | Activator$ Player | Amount$ 3 | Description$ Spells with the chosen name cost {3} more to cast.
|
||||
S:Mode$ CantBeActivated | ValidCard$ Card.NamedCard | ValidSA$ Activated.!ManaAbility | Description$ Activated abilities of sources with the chosen name can't be activated unless they're mana abilities.
|
||||
AI:RemoveDeck:Random
|
||||
Oracle:Flash\nAs Disruptor Flute enters, choose a card name.\nSpells with the chosen name cost 3 more to cast.\nActivated abilities of sources with the chosen name can't be activated unless they're mana abilities.
|
||||
Oracle:Flash\nAs Disruptor Flute enters, choose a card name.\nSpells with the chosen name cost {3} more to cast.\nActivated abilities of sources with the chosen name can't be activated unless they're mana abilities.
|
||||
|
||||
@@ -5,7 +5,7 @@ PT:2/2
|
||||
K:Trample
|
||||
K:etbCounter:P1P1:X:no Condition:NICKNAME enters with a +1/+1 counter on him for each land you control.
|
||||
SVar:X:Count$Valid Land.YouCtrl
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigChangeZone | TriggerDescription$ When NICKNAME dies, return this card to your hand.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When NICKNAME dies, return this card to your hand.
|
||||
SVar:TrigReturn:DB$ ChangeZone | Defined$ TriggeredNewCardLKICopy | Origin$ Graveyard | Destination$ Hand
|
||||
DeckHas:Ability$Counters
|
||||
Oracle:Trample (This creature can deal excess combat damage to the player it's attacking.)\nMichelangelo enters with a +1/+1 counter on him for each land you control.\nWhen Michelangelo dies, return this card to your hand.
|
||||
Reference in New Issue
Block a user