mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
- Fixed logic error in canBeSacrificedBy.
- Improved SacrificeAI.
This commit is contained in:
@@ -9195,7 +9195,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
System.out.println("Trying to sacrifice immutables: " + this);
|
||||
return false;
|
||||
}
|
||||
if (source != null && !getController().isOpponentOf(source.getActivatingPlayer())
|
||||
if (source != null && getController().isOpponentOf(source.getActivatingPlayer())
|
||||
&& getController().hasKeyword("Spells and abilities your opponents control can't cause you to sacrifice permanents.")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package forge.card.ability.ai;
|
||||
import java.util.List;
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.ability.SpellAbilityAi;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
@@ -20,42 +21,8 @@ public class SacrificeAi extends SpellAbilityAi {
|
||||
|
||||
@Override
|
||||
protected boolean canPlayAI(AIPlayer ai, SpellAbility sa) {
|
||||
boolean chance = sacrificeTgtAI(ai, sa);
|
||||
|
||||
// Some additional checks based on what is being sacrificed, and who is
|
||||
// sacrificing
|
||||
final Target tgt = sa.getTarget();
|
||||
if (tgt != null) {
|
||||
final String valid = sa.getParam("SacValid");
|
||||
String num = sa.getParam("Amount");
|
||||
num = (num == null) ? "1" : num;
|
||||
final int amount = AbilityUtils.calculateAmount(sa.getSourceCard(), num, sa);
|
||||
|
||||
List<Card> list =
|
||||
CardLists.getValidCards(ai.getOpponent().getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getSourceCard());
|
||||
|
||||
if (list.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Card source = sa.getSourceCard();
|
||||
if (num.equals("X") && source.getSVar(num).equals("Count$xPaid")) {
|
||||
// Set PayX here to maximum value.
|
||||
final int xPay = Math.min(ComputerUtilMana.determineLeftoverMana(sa, ai), amount);
|
||||
source.setSVar("PayX", Integer.toString(xPay));
|
||||
}
|
||||
|
||||
final int half = (amount / 2) + (amount % 2); // Half of amount
|
||||
// rounded up
|
||||
|
||||
// If the Human has at least half rounded up of the amount to be
|
||||
// sacrificed, cast the spell
|
||||
if (list.size() < half) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return chance;
|
||||
return sacrificeTgtAI(ai, sa);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,16 +49,49 @@ public class SacrificeAi extends SpellAbilityAi {
|
||||
|
||||
private boolean sacrificeTgtAI(final Player ai, final SpellAbility sa) {
|
||||
|
||||
final Card card = sa.getSourceCard();
|
||||
final Card source = sa.getSourceCard();
|
||||
final Target tgt = sa.getTarget();
|
||||
final boolean destroy = sa.hasParam("Destroy");
|
||||
|
||||
Player opp = ai.getOpponent();
|
||||
if (tgt != null) {
|
||||
tgt.resetTargets();
|
||||
if (opp.canBeTargetedBy(sa)) {
|
||||
tgt.addTarget(opp);
|
||||
return true;
|
||||
if (!opp.canBeTargetedBy(sa)) {
|
||||
return false;
|
||||
}
|
||||
tgt.addTarget(opp);
|
||||
final String valid = sa.getParam("SacValid");
|
||||
String num = sa.getParam("Amount");
|
||||
num = (num == null) ? "1" : num;
|
||||
final int amount = AbilityUtils.calculateAmount(sa.getSourceCard(), num, sa);
|
||||
|
||||
List<Card> list =
|
||||
CardLists.getValidCards(ai.getOpponent().getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getSourceCard());
|
||||
if (!destroy) {
|
||||
list = CardLists.filter(list, CardPredicates.canBeSacrificedBy(sa));
|
||||
} else {
|
||||
if (!CardLists.getKeyword(list, "Indestructible").isEmpty()) {
|
||||
// human can choose to destroy indestructibles
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (list.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (num.equals("X") && source.getSVar(num).equals("Count$xPaid")) {
|
||||
// Set PayX here to maximum value.
|
||||
final int xPay = Math.min(ComputerUtilMana.determineLeftoverMana(sa, ai), amount);
|
||||
source.setSVar("PayX", Integer.toString(xPay));
|
||||
}
|
||||
|
||||
final int half = (amount / 2) + (amount % 2); // Half of amount
|
||||
// rounded up
|
||||
|
||||
// If the Human has at least half rounded up of the amount to be
|
||||
// sacrificed, cast the spell
|
||||
if (!sa.isTrigger() && list.size() < half) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -108,9 +108,8 @@ public class SacrificeAi extends SpellAbilityAi {
|
||||
// TODO: Cast if the type is favorable: my "worst" valid is
|
||||
// worse than his "worst" valid
|
||||
final String num = sa.hasParam("Amount") ? sa.getParam("Amount") : "1";
|
||||
int amount = AbilityUtils.calculateAmount(card, num, sa);
|
||||
int amount = AbilityUtils.calculateAmount(source, num, sa);
|
||||
|
||||
final Card source = sa.getSourceCard();
|
||||
if (num.equals("X") && source.getSVar(num).equals("Count$xPaid")) {
|
||||
// Set PayX here to maximum value.
|
||||
amount = Math.min(ComputerUtilMana.determineLeftoverMana(sa, ai), amount);
|
||||
|
||||
@@ -3,6 +3,8 @@ package forge.card.ability.effects;
|
||||
import java.util.List;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.ability.SpellAbilityEffect;
|
||||
@@ -51,6 +53,9 @@ public class SacrificeEffect extends SpellAbilityEffect {
|
||||
for (final Player p : tgts) {
|
||||
List<Card> battlefield = p.getCardsIn(ZoneType.Battlefield);
|
||||
List<Card> validTargets = AbilityUtils.filterListByType(battlefield, valid, sa);
|
||||
if (!destroy) {
|
||||
validTargets = CardLists.filter(validTargets, CardPredicates.canBeSacrificedBy(sa));
|
||||
}
|
||||
|
||||
if (sa.hasParam("Random")) {
|
||||
choosenToSacrifice = Aggregates.random(validTargets, Math.min(amount, validTargets.size()));
|
||||
|
||||
Reference in New Issue
Block a user