mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 18:28:00 +00:00
Use ComputerUtilAbility.isFullyTargetable() and add more tests.
This commit is contained in:
@@ -54,6 +54,7 @@ import forge.game.replacement.ReplacementLayer;
|
|||||||
import forge.game.replacement.ReplacementType;
|
import forge.game.replacement.ReplacementType;
|
||||||
import forge.game.spellability.*;
|
import forge.game.spellability.*;
|
||||||
import forge.game.staticability.StaticAbility;
|
import forge.game.staticability.StaticAbility;
|
||||||
|
import forge.game.staticability.StaticAbilityMustTarget;
|
||||||
import forge.game.trigger.Trigger;
|
import forge.game.trigger.Trigger;
|
||||||
import forge.game.trigger.TriggerType;
|
import forge.game.trigger.TriggerType;
|
||||||
import forge.game.trigger.WrappedAbility;
|
import forge.game.trigger.WrappedAbility;
|
||||||
@@ -902,8 +903,13 @@ public class AiController {
|
|||||||
if (sa instanceof SpellPermanent) {
|
if (sa instanceof SpellPermanent) {
|
||||||
return canPlayFromEffectAI((SpellPermanent)sa, false, true);
|
return canPlayFromEffectAI((SpellPermanent)sa, false, true);
|
||||||
}
|
}
|
||||||
if (sa.usesTargeting() && !sa.hasLegalTargets()) {
|
if (sa.usesTargeting()) {
|
||||||
return AiPlayDecision.TargetingFailed;
|
if (!sa.isTargetNumberValid() && sa.getTargetRestrictions().getNumCandidates(sa, true) == 0) {
|
||||||
|
return AiPlayDecision.TargetingFailed;
|
||||||
|
}
|
||||||
|
if (!StaticAbilityMustTarget.meetsMustTargetRestriction(sa)) {
|
||||||
|
return AiPlayDecision.TargetingFailed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (sa instanceof Spell) {
|
if (sa instanceof Spell) {
|
||||||
if (!player.cantLoseForZeroOrLessLife() && player.canLoseLife() &&
|
if (!player.cantLoseForZeroOrLessLife() && player.canLoseLife() &&
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package forge.ai.simulation;
|
package forge.ai.simulation;
|
||||||
|
|
||||||
|
import forge.ai.ComputerUtilAbility;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@@ -53,7 +54,7 @@ public class SpellAbilityChoicesIterator {
|
|||||||
int origIndex = -1;
|
int origIndex = -1;
|
||||||
for (AbilitySub sub : choices) {
|
for (AbilitySub sub : choices) {
|
||||||
origIndex++;
|
origIndex++;
|
||||||
if (sub.usesTargeting() && !sub.hasLegalTargets()) {
|
if (!ComputerUtilAbility.isFullyTargetable(sub)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
modesMap.add(origIndex);
|
modesMap.add(origIndex);
|
||||||
|
|||||||
@@ -352,7 +352,7 @@ public class SpellAbilityPicker {
|
|||||||
if (!ComputerUtilCost.canPayCost(sa, player, sa.isTrigger())) {
|
if (!ComputerUtilCost.canPayCost(sa, player, sa.isTrigger())) {
|
||||||
return AiPlayDecision.CantAfford;
|
return AiPlayDecision.CantAfford;
|
||||||
}
|
}
|
||||||
if (sa.usesTargeting() && !sa.hasLegalTargets()) {
|
if (!ComputerUtilAbility.isFullyTargetable(sa)) {
|
||||||
return AiPlayDecision.TargetingFailed;
|
return AiPlayDecision.TargetingFailed;
|
||||||
}
|
}
|
||||||
if (shouldWaitForLater(sa)) {
|
if (shouldWaitForLater(sa)) {
|
||||||
|
|||||||
@@ -1655,16 +1655,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
return targetRestrictions != null;
|
return targetRestrictions != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasLegalTargets() {
|
|
||||||
if (!isTargetNumberValid() && getTargetRestrictions().getNumCandidates(this, true) == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!StaticAbilityMustTarget.meetsMustTargetRestriction(this)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TargetRestrictions getTargetRestrictions() {
|
public TargetRestrictions getTargetRestrictions() {
|
||||||
return targetRestrictions;
|
return targetRestrictions;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -566,4 +566,45 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest {
|
|||||||
// Only a single simulation expected (no target self).
|
// Only a single simulation expected (no target self).
|
||||||
AssertJUnit.assertEquals(1, picker.getNumSimulations());
|
AssertJUnit.assertEquals(1, picker.getNumSimulations());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testModalSpellNoTargetsForModeWithSubAbility() {
|
||||||
|
Game game = initAndCreateGame();
|
||||||
|
Player p = game.getPlayers().get(1);
|
||||||
|
Player opponent = game.getPlayers().get(0);
|
||||||
|
|
||||||
|
addCardToZone("Temur Charm", p, ZoneType.Hand);
|
||||||
|
addCard("Forest", p);
|
||||||
|
addCard("Island", p);
|
||||||
|
addCard("Mountain", p);
|
||||||
|
|
||||||
|
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
||||||
|
game.getAction().checkStateEffects(true);
|
||||||
|
|
||||||
|
SpellAbilityPicker picker = new SpellAbilityPicker(game, p);
|
||||||
|
SpellAbility sa = picker.chooseSpellAbilityToPlay(null);
|
||||||
|
// Only mode "Creatures with power 3 or less can’t block this turn" should be simulated.
|
||||||
|
AssertJUnit.assertEquals(1, picker.getNumSimulations());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testModalSpellNoTargetsForAnyModes() {
|
||||||
|
Game game = initAndCreateGame();
|
||||||
|
Player p = game.getPlayers().get(1);
|
||||||
|
Player opponent = game.getPlayers().get(0);
|
||||||
|
|
||||||
|
addCardToZone("Drown in the Loch", p, ZoneType.Hand);
|
||||||
|
addCard("Swamp", p);
|
||||||
|
addCard("Island", p);
|
||||||
|
|
||||||
|
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
||||||
|
game.getAction().checkStateEffects(true);
|
||||||
|
|
||||||
|
SpellAbilityPicker picker = new SpellAbilityPicker(game, p);
|
||||||
|
SpellAbility sa = picker.chooseSpellAbilityToPlay(null);
|
||||||
|
// TODO: Ideally, this would be 0 simulations, but we currently only determine there are no
|
||||||
|
// valid in SpellAbilityChoicesIterator, which runs once we're already simulating the spell.
|
||||||
|
// Still, this test case exercises the code path and ensures we don't crash in this case.
|
||||||
|
AssertJUnit.assertEquals(1, picker.getNumSimulations());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user