Haunt fix

This commit is contained in:
tool4EvEr
2023-04-24 09:47:32 +02:00
parent 60d4af0e10
commit f1e455de2a
11 changed files with 43 additions and 58 deletions

View File

@@ -432,7 +432,7 @@ public class ComputerUtilCard {
* @param list
* @return a {@link forge.game.card.Card} object.
*/
public static Card getBestCreatureToBounceAI(final CardCollectionView list) {
public static Card getBestCreatureToBounceAI(final Iterable<Card> list) {
if (Iterables.size(list) == 1) {
return Iterables.get(list, 0);
}

View File

@@ -86,7 +86,7 @@ public class PlayerControllerAi extends PlayerController {
@Override
public SpellAbility getAbilityToPlay(Card hostCard, List<SpellAbility> abilities, ITriggerEvent triggerEvent) {
if (abilities.size() == 0) {
if (abilities.isEmpty()) {
return null;
}
return abilities.get(0);

View File

@@ -1216,7 +1216,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
}
if (choice == null) { // can't find anything left
if (sa.getTargets().size() == 0 || !sa.isTargetNumberValid()) {
if (sa.getTargets().isEmpty() || !sa.isTargetNumberValid()) {
if (!mandatory) {
sa.resetTargets();
}
@@ -1432,7 +1432,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
final ZoneType destination = ZoneType.smartValueOf(sa.getParam("Destination"));
final TargetRestrictions tgt = sa.getTargetRestrictions();
CardCollection list = new CardCollection(CardUtil.getValidCardsToTarget(tgt, sa));
List<Card> list = CardUtil.getValidCardsToTarget(tgt, sa);
if (list.isEmpty()) {
return false;

View File

@@ -5,7 +5,6 @@ import java.util.Map;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.ai.AiController;
import forge.ai.AiPlayerPredicates;
@@ -197,8 +196,7 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
// mass zone change for creatures: if in dire danger, do it; otherwise, only do it if the opponent's
// creatures are better in value
if ((CardLists.getNotType(oppType, "Creature").size() == 0)
&& (CardLists.getNotType(computerType, "Creature").size() == 0)) {
if (CardLists.getNotType(oppType, "Creature").isEmpty() && CardLists.getNotType(computerType, "Creature").isEmpty()) {
if (game.getCombat() != null && ComputerUtilCombat.lifeInSeriousDanger(ai, game.getCombat())) {
if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)
&& game.getPhaseHandler().getPlayerTurn().isOpponentOf(ai)) {
@@ -225,17 +223,15 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
} else if (origin.equals(ZoneType.Graveyard)) {
if (sa.usesTargeting()) {
// search targetable Opponents
final Iterable<Player> oppList = Iterables.filter(ai.getOpponents(),
PlayerPredicates.isTargetableBy(sa));
final PlayerCollection oppList = ai.getOpponents().filter(PlayerPredicates.isTargetableBy(sa));
if (Iterables.isEmpty(oppList)) {
if (oppList.isEmpty()) {
return false;
}
// get the one with the most in graveyard
// zone is visible so evaluate which would be hurt the most
Player oppTarget = Collections.max(Lists.newArrayList(oppList),
AiPlayerPredicates.compareByZoneValue(sa.getParam("ChangeType"), origin, sa));
Player oppTarget = Collections.max(oppList, AiPlayerPredicates.compareByZoneValue(sa.getParam("ChangeType"), origin, sa));
// set the target
if (!oppTarget.getCardsIn(ZoneType.Graveyard).isEmpty()) {
@@ -270,18 +266,14 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
return (curHandSize + minAdv - 1 < numExiledWithSrc) || (!noDiscard && numExiledWithSrc >= ai.getMaxHandSize());
}
} else if (origin.equals(ZoneType.Stack)) {
// time stop can do something like this:
// Origin$ Stack | Destination$ Exile | SubAbility$ DBSkip
// DBSKipToPhase | DB$SkipToPhase | Phase$ Cleanup
// otherwise, this situation doesn't exist
// TODO
return false;
}
if (destination.equals(ZoneType.Battlefield)) {
if (sa.hasParam("GainControl")) {
// Check if the cards are valuable enough
if (CardLists.getNotType(oppType, "Creature").size() == 0
&& CardLists.getNotType(computerType, "Creature").size() == 0) {
if (CardLists.getNotType(oppType, "Creature").isEmpty() && CardLists.getNotType(computerType, "Creature").isEmpty()) {
if ((ComputerUtilCard.evaluateCreatureList(computerType) + ComputerUtilCard
.evaluateCreatureList(oppType)) < 400) {
return false;
@@ -294,8 +286,7 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
}
} else {
// don't activate if human gets more back than AI does
if ((CardLists.getNotType(oppType, "Creature").size() == 0)
&& (CardLists.getNotType(computerType, "Creature").size() == 0)) {
if (CardLists.getNotType(oppType, "Creature").isEmpty() && CardLists.getNotType(computerType, "Creature").isEmpty()) {
if (ComputerUtilCard.evaluateCreatureList(computerType) <= (ComputerUtilCard
.evaluateCreatureList(oppType) + 100)) {
return false;
@@ -354,8 +345,7 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
return true;
// if AI creature is better than Human Creature
return ComputerUtilCard.evaluateCreatureList(aiCards) >= ComputerUtilCard
.evaluateCreatureList(humanCards);
return ComputerUtilCard.evaluateCreatureList(aiCards) >= ComputerUtilCard.evaluateCreatureList(humanCards);
}
return true;
}
@@ -416,15 +406,13 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
// if the AI is using it defensively, then something else needs to occur
// if only creatures are affected evaluate both lists and pass only
// if human creatures are more valuable
if ((CardLists.getNotType(humanType, "Creature").isEmpty()) && (CardLists.getNotType(computerType, "Creature").isEmpty())) {
if (ComputerUtilCard.evaluateCreatureList(computerType) >= ComputerUtilCard
.evaluateCreatureList(humanType)) {
if (CardLists.getNotType(humanType, "Creature").isEmpty() && CardLists.getNotType(computerType, "Creature").isEmpty()) {
if (ComputerUtilCard.evaluateCreatureList(computerType) >= ComputerUtilCard.evaluateCreatureList(humanType)) {
return false;
}
} // otherwise evaluate both lists by CMC and pass only if human
// permanents are more valuable
else if (ComputerUtilCard.evaluatePermanentList(computerType) >= ComputerUtilCard
.evaluatePermanentList(humanType)) {
else if (ComputerUtilCard.evaluatePermanentList(computerType) >= ComputerUtilCard.evaluatePermanentList(humanType)) {
return false;
}
} else if (origin.equals(ZoneType.Graveyard)) {
@@ -457,11 +445,7 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
} else if (origin.equals(ZoneType.Exile)) {
} else if (origin.equals(ZoneType.Stack)) {
// time stop can do something like this:
// Origin$ Stack | Destination$ Exile | SubAbility$ DBSkip
// DBSKipToPhase | DB$SkipToPhase | Phase$ Cleanup
// otherwise, this situation doesn't exist
return false;
// currently only exists indirectly (e.g. Summary Dismissal via PlayAi)
}
if (destination.equals(ZoneType.Battlefield)) {
@@ -469,25 +453,22 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
if (mandatory) {
return true;
}
if (sa.getParam("GainControl") != null) {
if (sa.hasParam("GainControl")) {
// Check if the cards are valuable enough
if ((CardLists.getNotType(humanType, "Creature").size() == 0) && (CardLists.getNotType(computerType, "Creature").size() == 0)) {
return (ComputerUtilCard.evaluateCreatureList(computerType) + ComputerUtilCard
.evaluateCreatureList(humanType)) >= 1;
if (CardLists.getNotType(humanType, "Creature").isEmpty() && CardLists.getNotType(computerType, "Creature").isEmpty()) {
return (ComputerUtilCard.evaluateCreatureList(computerType) + ComputerUtilCard.evaluateCreatureList(humanType)) >= 1;
} // otherwise evaluate both lists by CMC and pass only if human
// permanents are less valuable
else return (ComputerUtilCard.evaluatePermanentList(computerType) + ComputerUtilCard
return (ComputerUtilCard.evaluatePermanentList(computerType) + ComputerUtilCard
.evaluatePermanentList(humanType)) >= 1;
} else {
// don't activate if human gets more back than AI does
if ((CardLists.getNotType(humanType, "Creature").isEmpty()) && (CardLists.getNotType(computerType, "Creature").isEmpty())) {
return ComputerUtilCard.evaluateCreatureList(computerType) > ComputerUtilCard
.evaluateCreatureList(humanType);
} // otherwise evaluate both lists by CMC and pass only if human
// permanents are less valuable
else return ComputerUtilCard.evaluatePermanentList(computerType) > ComputerUtilCard
.evaluatePermanentList(humanType);
}
// don't activate if human gets more back than AI does
if (CardLists.getNotType(humanType, "Creature").isEmpty() && CardLists.getNotType(computerType, "Creature").isEmpty()) {
return ComputerUtilCard.evaluateCreatureList(computerType) > ComputerUtilCard.evaluateCreatureList(humanType);
} // otherwise evaluate both lists by CMC and pass only if human
// permanents are less valuable
return ComputerUtilCard.evaluatePermanentList(computerType) > ComputerUtilCard.evaluatePermanentList(humanType);
}
return true;

View File

@@ -59,7 +59,7 @@ public class ClashAi extends SpellAbilityAi {
@Override
protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable<Player> options, Map<String, Object> params) {
for (Player p : options) {
if (p.getCardsIn(ZoneType.Library).size() == 0)
if (p.getCardsIn(ZoneType.Library).isEmpty())
return p;
}

View File

@@ -64,8 +64,7 @@ public class CounterAi extends SpellAbilityAi {
if (sa.usesTargeting()) {
final SpellAbility topSA = ComputerUtilAbility.getTopSpellAbilityOnStack(game, sa);
if ((topSA.isSpell() && !CardFactoryUtil.isCounterableBy(topSA.getHostCard(), sa)) || topSA.getActivatingPlayer() == ai
|| ai.getAllies().contains(topSA.getActivatingPlayer())) {
if ((topSA.isSpell() && !CardFactoryUtil.isCounterableBy(topSA.getHostCard(), sa)) || ai.getYourTeam().contains(topSA.getActivatingPlayer())) {
// might as well check for player's friendliness
return false;
} else if (sa.hasParam("ConditionWouldDestroy") && !CounterEffect.checkForConditionWouldDestroy(sa, topSA)) {

View File

@@ -89,7 +89,7 @@ public class RegenerateAi extends SpellAbilityAi {
// filter AIs battlefield by what I can target
List<Card> targetables = CardLists.getTargetableCards(ai.getCardsIn(ZoneType.Battlefield), sa);
if (targetables.size() == 0) {
if (targetables.isEmpty()) {
return false;
}
@@ -153,11 +153,11 @@ public class RegenerateAi extends SpellAbilityAi {
CardCollectionView targetables = CardLists.getTargetableCards(game.getCardsIn(ZoneType.Battlefield), sa);
final List<Card> compTargetables = CardLists.filterControlledBy(targetables, ai);
if (targetables.size() == 0) {
if (targetables.isEmpty()) {
return false;
}
if (!mandatory && compTargetables.size() == 0) {
if (!mandatory && compTargetables.isEmpty()) {
return false;
}

View File

@@ -32,7 +32,7 @@ public class RegenerateAllAi extends SpellAbilityAi {
list = CardLists.getValidCards(list, valid, hostCard.getController(), hostCard, sa);
list = CardLists.filter(list, CardPredicates.isController(ai));
if (list.size() == 0) {
if (list.isEmpty()) {
return false;
}

View File

@@ -339,7 +339,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
final String fromGraveyard = " from the graveyard";
if (destination.equals(ZoneType.Battlefield)) {
final boolean attacking = (sa.hasParam("Attacking"));
final boolean attacking = sa.hasParam("Attacking");
if (ZoneType.Graveyard.equals(origin)) {
sb.append("Return").append(targetname).append(fromGraveyard).append(" to the battlefield");
} else {
@@ -565,6 +565,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
// If a card is moved to library from the stack, remove its spells from the stack
if (sa.hasParam("Fizzle")) {
// TODO only AI still targets as card, try to remove it
if (gameCard.isInZone(ZoneType.Exile) || gameCard.isInZone(ZoneType.Hand) || gameCard.isInZone(ZoneType.Stack)) {
// This only fizzles spells, not anything else.
game.getStack().remove(gameCard);

View File

@@ -1318,8 +1318,8 @@ public class CardFactoryUtil {
// Second, create the trigger that runs when the haunted creature dies
final StringBuilder sbDies = new StringBuilder();
sbDies.append("Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | TriggerZones$ Exile |");
sbDies.append("ValidCard$ Creature.HauntedBy | Execute$ ").append(hauntSVarName);
sbDies.append("Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | TriggerZones$ Exile");
sbDies.append(" | ValidCard$ Creature.HauntedBy | Execute$ ").append(hauntSVarName);
sbDies.append(" | TriggerDescription$ ").append(hauntDescription);
final Trigger hauntedDies = TriggerHandler.parseTrigger(sbDies.toString(), card, intrinsic);
@@ -1369,7 +1369,7 @@ public class CardFactoryUtil {
// First, create trigger that runs when the haunter goes to the graveyard
final StringBuilder sbHaunter = new StringBuilder();
sbHaunter.append("Mode$ ChangesZone | Origin$ ");
sbHaunter.append(card.isCreature() ? "Battlefield" : "Stack | ResolvedCard$ True");
sbHaunter.append(card.isCreature() ? "Battlefield" : "Stack | Fizzle$ False");
sbHaunter.append(" | Destination$ Graveyard | ValidCard$ Card.Self");
sbHaunter.append(" | Secondary$ True | TriggerDescription$ Haunt (").append(inst.getReminderText()).append(")");

View File

@@ -135,10 +135,14 @@ public class TriggerChangesZone extends Trigger {
}
}
if (hasParam("ResolvedCard")) {
if (hasParam("Fizzle")) {
if (!runParams.containsKey(AbilityKey.Fizzle)) {
return false;
}
Boolean val = (Boolean) runParams.get(AbilityKey.Fizzle);
if ("True".equals(getParam("Fizzle")) != val) {
return false;
}
}
// Check number of lands ETB this turn on triggered card's controller