mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
- Improve AI logic for Tetzimoc, Primal Death; ensure that the AI actually plays it (used not to play at all).
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package forge.ai.ability;
|
package forge.ai.ability;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.base.Predicates;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import forge.ai.*;
|
import forge.ai.*;
|
||||||
@@ -125,6 +126,8 @@ public class CountersPutAi extends SpellAbilityAi {
|
|||||||
final String type = sa.getParam("CounterType");
|
final String type = sa.getParam("CounterType");
|
||||||
final String amountStr = sa.getParam("CounterNum");
|
final String amountStr = sa.getParam("CounterNum");
|
||||||
final boolean divided = sa.hasParam("DividedAsYouChoose");
|
final boolean divided = sa.hasParam("DividedAsYouChoose");
|
||||||
|
final String logic = sa.getParamOrDefault("AILogic", "");
|
||||||
|
PhaseHandler ph = ai.getGame().getPhaseHandler();
|
||||||
|
|
||||||
final boolean isClockwork = "True".equals(sa.getParam("UpTo")) && "Self".equals(sa.getParam("Defined"))
|
final boolean isClockwork = "True".equals(sa.getParam("UpTo")) && "Self".equals(sa.getParam("Defined"))
|
||||||
&& "P1P0".equals(sa.getParam("CounterType")) && "Count$xPaid".equals(source.getSVar("X"))
|
&& "P1P0".equals(sa.getParam("CounterType")) && "Count$xPaid".equals(source.getSVar("X"))
|
||||||
@@ -214,15 +217,15 @@ public class CountersPutAi extends SpellAbilityAi {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("Never".equals(sa.getParam("AILogic"))) {
|
if ("Never".equals(logic)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("PayEnergy".equals(sa.getParam("AILogic"))) {
|
if ("PayEnergy".equals(logic)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("PayEnergyConservatively".equals(sa.getParam("AILogic"))) {
|
if ("PayEnergyConservatively".equals(logic)) {
|
||||||
boolean onlyInCombat = ai.getController().isAI()
|
boolean onlyInCombat = ai.getController().isAI()
|
||||||
&& ((PlayerControllerAi) ai.getController()).getAi().getBooleanProperty(AiProps.CONSERVATIVE_ENERGY_PAYMENT_ONLY_IN_COMBAT);
|
&& ((PlayerControllerAi) ai.getController()).getAi().getBooleanProperty(AiProps.CONSERVATIVE_ENERGY_PAYMENT_ONLY_IN_COMBAT);
|
||||||
boolean onlyDefensive = ai.getController().isAI()
|
boolean onlyDefensive = ai.getController().isAI()
|
||||||
@@ -264,6 +267,22 @@ public class CountersPutAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (logic.equals("MarkOppCreature")) {
|
||||||
|
if (!ph.is(PhaseType.END_OF_TURN)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CardCollection oppCreats = CardLists.filter(ai.getOpponents().getCreaturesInPlay(),
|
||||||
|
Predicates.not(CardPredicates.hasCounter(CounterType.getType(type))));
|
||||||
|
|
||||||
|
if (!oppCreats.isEmpty()) {
|
||||||
|
Card bestCreat = ComputerUtilCard.getBestCreatureAI(oppCreats);
|
||||||
|
sa.resetTargets();
|
||||||
|
sa.getTargets().add(bestCreat);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sa.getConditions() != null && !sa.getConditions().areMet(sa) && sa.getSubAbility() == null) {
|
if (sa.getConditions() != null && !sa.getConditions().areMet(sa) && sa.getSubAbility() == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -292,7 +311,7 @@ public class CountersPutAi extends SpellAbilityAi {
|
|||||||
// TODO handle proper calculation of X values based on Cost
|
// TODO handle proper calculation of X values based on Cost
|
||||||
int amount = AbilityUtils.calculateAmount(source, amountStr, sa);
|
int amount = AbilityUtils.calculateAmount(source, amountStr, sa);
|
||||||
|
|
||||||
if ("Fight".equals(sa.getParam("AILogic"))) {
|
if ("Fight".equals(logic)) {
|
||||||
int nPump = 0;
|
int nPump = 0;
|
||||||
if (type.equals("P1P1")) {
|
if (type.equals("P1P1")) {
|
||||||
nPump = amount;
|
nPump = amount;
|
||||||
@@ -323,7 +342,7 @@ public class CountersPutAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
source.setSVar("PayX", Integer.toString(amount));
|
source.setSVar("PayX", Integer.toString(amount));
|
||||||
} else if ("ExiledCreatureFromGraveCMC".equals(sa.getParam("AILogic"))) {
|
} else if ("ExiledCreatureFromGraveCMC".equals(logic)) {
|
||||||
// e.g. Necropolis
|
// e.g. Necropolis
|
||||||
amount = Aggregates.max(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES), CardPredicates.Accessors.fnGetCmc);
|
amount = Aggregates.max(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES), CardPredicates.Accessors.fnGetCmc);
|
||||||
if (amount > 0 && ai.getGame().getPhaseHandler().is(PhaseType.END_OF_TURN)) {
|
if (amount > 0 && ai.getGame().getPhaseHandler().is(PhaseType.END_OF_TURN)) {
|
||||||
@@ -337,7 +356,7 @@ public class CountersPutAi extends SpellAbilityAi {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("Polukranos".equals(sa.getParam("AILogic"))) {
|
if ("Polukranos".equals(logic)) {
|
||||||
|
|
||||||
CardCollection humCreatures = CardLists.getTargetableCards(ai.getOpponents().getCreaturesInPlay(), sa);
|
CardCollection humCreatures = CardLists.getTargetableCards(ai.getOpponents().getCreaturesInPlay(), sa);
|
||||||
|
|
||||||
@@ -360,9 +379,7 @@ public class CountersPutAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PhaseHandler ph = ai.getGame().getPhaseHandler();
|
if ("AlwaysAtOppEOT".equals(logic)) {
|
||||||
|
|
||||||
if ("AlwaysAtOppEOT".equals(sa.getParam("AILogic"))) {
|
|
||||||
if (ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn().equals(ai)) {
|
if (ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn().equals(ai)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -566,6 +583,7 @@ public class CountersPutAi extends SpellAbilityAi {
|
|||||||
final Game game = ai.getGame();
|
final Game game = ai.getGame();
|
||||||
Card choice = null;
|
Card choice = null;
|
||||||
final String type = sa.getParam("CounterType");
|
final String type = sa.getParam("CounterType");
|
||||||
|
final String logic = sa.getParamOrDefault("AILogic", "");
|
||||||
|
|
||||||
final String amountStr = sa.getParam("CounterNum");
|
final String amountStr = sa.getParam("CounterNum");
|
||||||
final boolean divided = sa.hasParam("DividedAsYouChoose");
|
final boolean divided = sa.hasParam("DividedAsYouChoose");
|
||||||
@@ -611,7 +629,7 @@ public class CountersPutAi extends SpellAbilityAi {
|
|||||||
SpellAbility animate = sa.findSubAbilityByType(ApiType.Animate);
|
SpellAbility animate = sa.findSubAbilityByType(ApiType.Animate);
|
||||||
if (!lands.isEmpty() && animate != null) {
|
if (!lands.isEmpty() && animate != null) {
|
||||||
choice = ComputerUtilCard.getWorstLand(lands);
|
choice = ComputerUtilCard.getWorstLand(lands);
|
||||||
} else if ("BoonCounterOnOppCreature".equals(sa.getParam("AILogic"))) {
|
} else if ("BoonCounterOnOppCreature".equals(logic)) {
|
||||||
choice = ComputerUtilCard.getWorstCreatureAI(list);
|
choice = ComputerUtilCard.getWorstCreatureAI(list);
|
||||||
} else {
|
} else {
|
||||||
choice = CountersAi.chooseBoonTarget(list, type);
|
choice = CountersAi.chooseBoonTarget(list, type);
|
||||||
|
|||||||
@@ -64,10 +64,15 @@ public class DestroyAllAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
public boolean doMassRemovalLogic(Player ai, SpellAbility sa) {
|
public boolean doMassRemovalLogic(Player ai, SpellAbility sa) {
|
||||||
final Card source = sa.getHostCard();
|
final Card source = sa.getHostCard();
|
||||||
|
final String logic = sa.getParamOrDefault("AILogic", "");
|
||||||
Player opponent = ComputerUtil.getOpponentFor(ai); // TODO: how should this AI logic work for multiplayer and getOpponents()?
|
Player opponent = ComputerUtil.getOpponentFor(ai); // TODO: how should this AI logic work for multiplayer and getOpponents()?
|
||||||
|
|
||||||
final int CREATURE_EVAL_THRESHOLD = 200;
|
final int CREATURE_EVAL_THRESHOLD = 200;
|
||||||
|
|
||||||
|
if (logic.equals("Always")) {
|
||||||
|
return true; // e.g. Tetzimoc, Primal Death, where we want to cast the permanent even if the removal trigger does nothing
|
||||||
|
}
|
||||||
|
|
||||||
String valid = "";
|
String valid = "";
|
||||||
if (sa.hasParam("ValidCards")) {
|
if (sa.hasParam("ValidCards")) {
|
||||||
valid = sa.getParam("ValidCards");
|
valid = sa.getParam("ValidCards");
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ ManaCost:4 B B
|
|||||||
Types:Legendary Creature Elder Dinosaur
|
Types:Legendary Creature Elder Dinosaur
|
||||||
PT:6/6
|
PT:6/6
|
||||||
K:Deathtouch
|
K:Deathtouch
|
||||||
A:AB$ PutCounter | Cost$ B | ActivationZone$ Hand | CostDesc$ {B}, Reveal CARDNAME from your hand: | PlayerTurn$ True | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ PREY | CounterNum$ 1 | IsCurse$ True | SpellDescription$ Put a prey counter on target creature. Activate this ability only during your turn.
|
A:AB$ PutCounter | Cost$ B | ActivationZone$ Hand | CostDesc$ {B}, Reveal CARDNAME from your hand: | PlayerTurn$ True | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ PREY | CounterNum$ 1 | IsCurse$ True | AILogic$ MarkOppCreature | SpellDescription$ Put a prey counter on target creature. Activate this ability only during your turn.
|
||||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDestroyAll | TriggerDescription$ When CARDNAME enters the battlefield, destroy each creature your opponents control with a prey counter on it.
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDestroyAll | TriggerDescription$ When CARDNAME enters the battlefield, destroy each creature your opponents control with a prey counter on it.
|
||||||
SVar:TrigDestroyAll:DB$ DestroyAll | ValidCards$ Creature.OppCtrl+counters_GE1_PREY
|
SVar:TrigDestroyAll:DB$ DestroyAll | ValidCards$ Creature.OppCtrl+counters_GE1_PREY | AILogic$ Always
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/tetzimoc_primal_death.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/tetzimoc_primal_death.jpg
|
||||||
Oracle:Deathtouch\n{B}, Reveal Tetzimoc, Primal Death from your hand: Put a prey counter on target creature. Activate this ability only during your turn.\nWhen Tetzimoc enters the battlefield, destroy each creature your opponents control with a prey counter on it.
|
Oracle:Deathtouch\n{B}, Reveal Tetzimoc, Primal Death from your hand: Put a prey counter on target creature. Activate this ability only during your turn.\nWhen Tetzimoc enters the battlefield, destroy each creature your opponents control with a prey counter on it.
|
||||||
Reference in New Issue
Block a user