mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 02:38:02 +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;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import forge.ai.*;
|
||||
@@ -125,6 +126,8 @@ public class CountersPutAi extends SpellAbilityAi {
|
||||
final String type = sa.getParam("CounterType");
|
||||
final String amountStr = sa.getParam("CounterNum");
|
||||
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"))
|
||||
&& "P1P0".equals(sa.getParam("CounterType")) && "Count$xPaid".equals(source.getSVar("X"))
|
||||
@@ -214,15 +217,15 @@ public class CountersPutAi extends SpellAbilityAi {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ("Never".equals(sa.getParam("AILogic"))) {
|
||||
if ("Never".equals(logic)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ("PayEnergy".equals(sa.getParam("AILogic"))) {
|
||||
if ("PayEnergy".equals(logic)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ("PayEnergyConservatively".equals(sa.getParam("AILogic"))) {
|
||||
if ("PayEnergyConservatively".equals(logic)) {
|
||||
boolean onlyInCombat = ai.getController().isAI()
|
||||
&& ((PlayerControllerAi) ai.getController()).getAi().getBooleanProperty(AiProps.CONSERVATIVE_ENERGY_PAYMENT_ONLY_IN_COMBAT);
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
@@ -292,7 +311,7 @@ public class CountersPutAi extends SpellAbilityAi {
|
||||
// TODO handle proper calculation of X values based on Cost
|
||||
int amount = AbilityUtils.calculateAmount(source, amountStr, sa);
|
||||
|
||||
if ("Fight".equals(sa.getParam("AILogic"))) {
|
||||
if ("Fight".equals(logic)) {
|
||||
int nPump = 0;
|
||||
if (type.equals("P1P1")) {
|
||||
nPump = amount;
|
||||
@@ -323,7 +342,7 @@ public class CountersPutAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
source.setSVar("PayX", Integer.toString(amount));
|
||||
} else if ("ExiledCreatureFromGraveCMC".equals(sa.getParam("AILogic"))) {
|
||||
} else if ("ExiledCreatureFromGraveCMC".equals(logic)) {
|
||||
// e.g. Necropolis
|
||||
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)) {
|
||||
@@ -337,7 +356,7 @@ public class CountersPutAi extends SpellAbilityAi {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ("Polukranos".equals(sa.getParam("AILogic"))) {
|
||||
if ("Polukranos".equals(logic)) {
|
||||
|
||||
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(sa.getParam("AILogic"))) {
|
||||
if ("AlwaysAtOppEOT".equals(logic)) {
|
||||
if (ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn().equals(ai)) {
|
||||
return true;
|
||||
}
|
||||
@@ -566,6 +583,7 @@ public class CountersPutAi extends SpellAbilityAi {
|
||||
final Game game = ai.getGame();
|
||||
Card choice = null;
|
||||
final String type = sa.getParam("CounterType");
|
||||
final String logic = sa.getParamOrDefault("AILogic", "");
|
||||
|
||||
final String amountStr = sa.getParam("CounterNum");
|
||||
final boolean divided = sa.hasParam("DividedAsYouChoose");
|
||||
@@ -611,7 +629,7 @@ public class CountersPutAi extends SpellAbilityAi {
|
||||
SpellAbility animate = sa.findSubAbilityByType(ApiType.Animate);
|
||||
if (!lands.isEmpty() && animate != null) {
|
||||
choice = ComputerUtilCard.getWorstLand(lands);
|
||||
} else if ("BoonCounterOnOppCreature".equals(sa.getParam("AILogic"))) {
|
||||
} else if ("BoonCounterOnOppCreature".equals(logic)) {
|
||||
choice = ComputerUtilCard.getWorstCreatureAI(list);
|
||||
} else {
|
||||
choice = CountersAi.chooseBoonTarget(list, type);
|
||||
|
||||
@@ -64,10 +64,15 @@ public class DestroyAllAi extends SpellAbilityAi {
|
||||
|
||||
public boolean doMassRemovalLogic(Player ai, SpellAbility sa) {
|
||||
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()?
|
||||
|
||||
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 = "";
|
||||
if (sa.hasParam("ValidCards")) {
|
||||
valid = sa.getParam("ValidCards");
|
||||
|
||||
@@ -3,8 +3,8 @@ ManaCost:4 B B
|
||||
Types:Legendary Creature Elder Dinosaur
|
||||
PT:6/6
|
||||
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.
|
||||
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
|
||||
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