mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 20:28: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);
|
System.out.println("Trying to sacrifice immutables: " + this);
|
||||||
return false;
|
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.")) {
|
&& getController().hasKeyword("Spells and abilities your opponents control can't cause you to sacrifice permanents.")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package forge.card.ability.ai;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import forge.Card;
|
import forge.Card;
|
||||||
import forge.CardLists;
|
import forge.CardLists;
|
||||||
|
import forge.CardPredicates;
|
||||||
import forge.card.ability.AbilityUtils;
|
import forge.card.ability.AbilityUtils;
|
||||||
import forge.card.ability.SpellAbilityAi;
|
import forge.card.ability.SpellAbilityAi;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
@@ -20,42 +21,8 @@ public class SacrificeAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canPlayAI(AIPlayer ai, SpellAbility sa) {
|
protected boolean canPlayAI(AIPlayer ai, SpellAbility sa) {
|
||||||
boolean chance = sacrificeTgtAI(ai, sa);
|
|
||||||
|
|
||||||
// Some additional checks based on what is being sacrificed, and who is
|
return sacrificeTgtAI(ai, sa);
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -82,16 +49,49 @@ public class SacrificeAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
private boolean sacrificeTgtAI(final Player ai, final SpellAbility sa) {
|
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 Target tgt = sa.getTarget();
|
||||||
|
final boolean destroy = sa.hasParam("Destroy");
|
||||||
|
|
||||||
Player opp = ai.getOpponent();
|
Player opp = ai.getOpponent();
|
||||||
if (tgt != null) {
|
if (tgt != null) {
|
||||||
tgt.resetTargets();
|
tgt.resetTargets();
|
||||||
if (opp.canBeTargetedBy(sa)) {
|
if (!opp.canBeTargetedBy(sa)) {
|
||||||
tgt.addTarget(opp);
|
return false;
|
||||||
return true;
|
}
|
||||||
|
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 {
|
} 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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,9 +108,8 @@ public class SacrificeAi extends SpellAbilityAi {
|
|||||||
// TODO: Cast if the type is favorable: my "worst" valid is
|
// TODO: Cast if the type is favorable: my "worst" valid is
|
||||||
// worse than his "worst" valid
|
// worse than his "worst" valid
|
||||||
final String num = sa.hasParam("Amount") ? sa.getParam("Amount") : "1";
|
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")) {
|
if (num.equals("X") && source.getSVar(num).equals("Count$xPaid")) {
|
||||||
// Set PayX here to maximum value.
|
// Set PayX here to maximum value.
|
||||||
amount = Math.min(ComputerUtilMana.determineLeftoverMana(sa, ai), amount);
|
amount = Math.min(ComputerUtilMana.determineLeftoverMana(sa, ai), amount);
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package forge.card.ability.effects;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import forge.Card;
|
import forge.Card;
|
||||||
|
import forge.CardLists;
|
||||||
|
import forge.CardPredicates;
|
||||||
import forge.Singletons;
|
import forge.Singletons;
|
||||||
import forge.card.ability.AbilityUtils;
|
import forge.card.ability.AbilityUtils;
|
||||||
import forge.card.ability.SpellAbilityEffect;
|
import forge.card.ability.SpellAbilityEffect;
|
||||||
@@ -51,6 +53,9 @@ public class SacrificeEffect extends SpellAbilityEffect {
|
|||||||
for (final Player p : tgts) {
|
for (final Player p : tgts) {
|
||||||
List<Card> battlefield = p.getCardsIn(ZoneType.Battlefield);
|
List<Card> battlefield = p.getCardsIn(ZoneType.Battlefield);
|
||||||
List<Card> validTargets = AbilityUtils.filterListByType(battlefield, valid, sa);
|
List<Card> validTargets = AbilityUtils.filterListByType(battlefield, valid, sa);
|
||||||
|
if (!destroy) {
|
||||||
|
validTargets = CardLists.filter(validTargets, CardPredicates.canBeSacrificedBy(sa));
|
||||||
|
}
|
||||||
|
|
||||||
if (sa.hasParam("Random")) {
|
if (sa.hasParam("Random")) {
|
||||||
choosenToSacrifice = Aggregates.random(validTargets, Math.min(amount, validTargets.size()));
|
choosenToSacrifice = Aggregates.random(validTargets, Math.min(amount, validTargets.size()));
|
||||||
|
|||||||
Reference in New Issue
Block a user