mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-14 17:58:01 +00:00
Fix Fatal Lore (#4488)
Co-authored-by: tool4EvEr <tool4EvEr@192.168.0.59>
This commit is contained in:
@@ -37,11 +37,6 @@ public class CharmAi extends SpellAbilityAi {
|
|||||||
min = sa.hasParam("MinCharmNum") ? AbilityUtils.calculateAmount(source, sa.getParam("MinCharmNum"), sa) : num;
|
min = sa.hasParam("MinCharmNum") ? AbilityUtils.calculateAmount(source, sa.getParam("MinCharmNum"), sa) : num;
|
||||||
}
|
}
|
||||||
|
|
||||||
// only randomize if not all possible together
|
|
||||||
if (num < choices.size() || source.hasKeyword(Keyword.ESCALATE)) {
|
|
||||||
Collections.shuffle(choices);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean timingRight = sa.isTrigger(); //is there a reason to play the charm now?
|
boolean timingRight = sa.isTrigger(); //is there a reason to play the charm now?
|
||||||
|
|
||||||
// Reset the chosen list otherwise it will be locked in forever by earlier calls
|
// Reset the chosen list otherwise it will be locked in forever by earlier calls
|
||||||
@@ -51,11 +46,15 @@ public class CharmAi extends SpellAbilityAi {
|
|||||||
if (!ai.equals(sa.getActivatingPlayer())) {
|
if (!ai.equals(sa.getActivatingPlayer())) {
|
||||||
// This branch is for "An Opponent chooses" Charm spells from Alliances
|
// This branch is for "An Opponent chooses" Charm spells from Alliances
|
||||||
// Current just choose the first available spell, which seem generally less disastrous for the AI.
|
// Current just choose the first available spell, which seem generally less disastrous for the AI.
|
||||||
//return choices.subList(0, 1);
|
|
||||||
chosenList = choices.subList(1, choices.size());
|
chosenList = choices.subList(1, choices.size());
|
||||||
} else if ("Triskaidekaphobia".equals(ComputerUtilAbility.getAbilitySourceName(sa))) {
|
} else if ("Triskaidekaphobia".equals(ComputerUtilAbility.getAbilitySourceName(sa))) {
|
||||||
chosenList = chooseTriskaidekaphobia(choices, ai);
|
chosenList = chooseTriskaidekaphobia(choices, ai);
|
||||||
} else {
|
} else {
|
||||||
|
// only randomize if not all possible together
|
||||||
|
if (num < choices.size() || source.hasKeyword(Keyword.ESCALATE)) {
|
||||||
|
Collections.shuffle(choices);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The generic chooseOptionsAi uses canPlayAi() to determine good choices
|
* The generic chooseOptionsAi uses canPlayAi() to determine good choices
|
||||||
* which means most "bonus" effects like life-gain and random pumps will
|
* which means most "bonus" effects like life-gain and random pumps will
|
||||||
|
|||||||
@@ -916,6 +916,7 @@ public final class GameActionUtil {
|
|||||||
if (ability.getApi() == ApiType.Charm) {
|
if (ability.getApi() == ApiType.Charm) {
|
||||||
// reset chain
|
// reset chain
|
||||||
ability.setSubAbility(null);
|
ability.setSubAbility(null);
|
||||||
|
ability.setChosenList(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
ability.clearTargets();
|
ability.clearTargets();
|
||||||
|
|||||||
@@ -1050,7 +1050,7 @@ public class AbilityUtils {
|
|||||||
addPlayer(card.getRemembered(), defined, players);
|
addPlayer(card.getRemembered(), defined, players);
|
||||||
}
|
}
|
||||||
else if (defined.startsWith("Imprinted")) {
|
else if (defined.startsWith("Imprinted")) {
|
||||||
addPlayer(Lists.newArrayList(card.getImprintedCards()), defined, players);
|
addPlayer(card.getImprintedCards(), defined, players);
|
||||||
}
|
}
|
||||||
else if (defined.startsWith("EffectSource")) {
|
else if (defined.startsWith("EffectSource")) {
|
||||||
Card root = findEffectRoot(card);
|
Card root = findEffectRoot(card);
|
||||||
@@ -1093,9 +1093,9 @@ public class AbilityUtils {
|
|||||||
o = ((SpellAbility) c).getActivatingPlayer();
|
o = ((SpellAbility) c).getActivatingPlayer();
|
||||||
} else if (c instanceof Iterable<?>) { // For merged permanent
|
} else if (c instanceof Iterable<?>) { // For merged permanent
|
||||||
if (orCont) {
|
if (orCont) {
|
||||||
addPlayer(ImmutableList.copyOf(Iterables.filter((Iterable<Object>)c, Player.class)), "", players);
|
addPlayer(Iterables.filter((Iterable<Object>)c, Player.class), "", players);
|
||||||
}
|
}
|
||||||
addPlayer(ImmutableList.copyOf(Iterables.filter((Iterable<Object>)c, Card.class)), "Controller", players);
|
addPlayer(Iterables.filter((Iterable<Object>)c, Card.class), "Controller", players);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (defParsed.endsWith("Opponent")) {
|
else if (defParsed.endsWith("Opponent")) {
|
||||||
@@ -1205,6 +1205,9 @@ public class AbilityUtils {
|
|||||||
else if (defined.equals("DefendingPlayer")) {
|
else if (defined.equals("DefendingPlayer")) {
|
||||||
players.add(game.getCombat().getDefendingPlayerRelatedTo(card));
|
players.add(game.getCombat().getDefendingPlayerRelatedTo(card));
|
||||||
}
|
}
|
||||||
|
else if (defined.equals("ChoosingPlayer")) {
|
||||||
|
players.add(((SpellAbility) sa).getRootAbility().getChoosingPlayer());
|
||||||
|
}
|
||||||
else if (defined.equals("ChosenPlayer")) {
|
else if (defined.equals("ChosenPlayer")) {
|
||||||
final Player p = card.getChosenPlayer();
|
final Player p = card.getChosenPlayer();
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
@@ -1212,7 +1215,7 @@ public class AbilityUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (defined.startsWith("ChosenCard")) {
|
else if (defined.startsWith("ChosenCard")) {
|
||||||
addPlayer(Lists.newArrayList(card.getChosenCards()), defined, players);
|
addPlayer(card.getChosenCards(), defined, players);
|
||||||
}
|
}
|
||||||
else if (defined.equals("SourceController")) {
|
else if (defined.equals("SourceController")) {
|
||||||
players.add(sa.getHostCard().getController());
|
players.add(sa.getHostCard().getController());
|
||||||
@@ -3053,11 +3056,11 @@ public class AbilityUtils {
|
|||||||
return applyAbilityTextChangeEffects(val, ability);
|
return applyAbilityTextChangeEffects(val, ability);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addPlayer(Iterable<Object> objects, final String def, FCollection<Player> players) {
|
private static void addPlayer(Iterable<?> objects, final String def, FCollection<Player> players) {
|
||||||
addPlayer(objects, def, players, false);
|
addPlayer(objects, def, players, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addPlayer(Iterable<Object> objects, final String def, FCollection<Player> players, boolean skipRemembered) {
|
private static void addPlayer(Iterable<?> objects, final String def, FCollection<Player> players, boolean skipRemembered) {
|
||||||
for (Object o : objects) {
|
for (Object o : objects) {
|
||||||
if (o instanceof Player) {
|
if (o instanceof Player) {
|
||||||
final Player p = (Player) o;
|
final Player p = (Player) o;
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ public class CharmEffect extends SpellAbilityEffect {
|
|||||||
//String choosers = sa.getParam("Chooser");
|
//String choosers = sa.getParam("Chooser");
|
||||||
FCollection<Player> opponents = activator.getOpponents(); // all cards have Choser$ Opponent, so it's hardcoded here
|
FCollection<Player> opponents = activator.getOpponents(); // all cards have Choser$ Opponent, so it's hardcoded here
|
||||||
chooser = activator.getController().chooseSingleEntityForEffect(opponents, sa, "Choose an opponent", null);
|
chooser = activator.getController().chooseSingleEntityForEffect(opponents, sa, "Choose an opponent", null);
|
||||||
source.setChosenPlayer(chooser);
|
sa.setChoosingPlayer(chooser);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AbilitySub> chosen = chooser.getController().chooseModeForAbility(sa, choices, min, num, canRepeat);
|
List<AbilitySub> chosen = chooser.getController().chooseModeForAbility(sa, choices, min, num, canRepeat);
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public class CardFactory {
|
|||||||
out = assignNewId ? getCard(in.getPaperCard(), in.getOwner(), in.getGame())
|
out = assignNewId ? getCard(in.getPaperCard(), in.getOwner(), in.getGame())
|
||||||
: getCard(in.getPaperCard(), in.getOwner(), in.getId(), in.getGame());
|
: getCard(in.getPaperCard(), in.getOwner(), in.getId(), in.getGame());
|
||||||
} else { // token
|
} else { // token
|
||||||
out = CardFactory.copyStats(in, in.getController(), assignNewId);
|
out = copyStats(in, in.getController(), assignNewId);
|
||||||
out.setToken(true);
|
out.setToken(true);
|
||||||
|
|
||||||
// need to copy this values for the tokens
|
// need to copy this values for the tokens
|
||||||
@@ -128,7 +128,7 @@ public class CardFactory {
|
|||||||
int id = game.nextCardId();
|
int id = game.nextCardId();
|
||||||
|
|
||||||
// need to create a physical card first, i need the original card faces
|
// need to create a physical card first, i need the original card faces
|
||||||
final Card copy = CardFactory.getCard(original.getPaperCard(), controller, id, game);
|
final Card copy = getCard(original.getPaperCard(), controller, id, game);
|
||||||
|
|
||||||
if (original.isTransformable()) {
|
if (original.isTransformable()) {
|
||||||
// 707.8a If an effect creates a token that is a copy of a transforming permanent or a transforming double-faced card not on the battlefield,
|
// 707.8a If an effect creates a token that is a copy of a transforming permanent or a transforming double-faced card not on the battlefield,
|
||||||
@@ -530,7 +530,7 @@ public class CardFactory {
|
|||||||
c.setSetCode(in.getSetCode());
|
c.setSetCode(in.getSetCode());
|
||||||
|
|
||||||
for (final CardStateName state : in.getStates()) {
|
for (final CardStateName state : in.getStates()) {
|
||||||
CardFactory.copyState(in, state, c, state);
|
copyState(in, state, c, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
c.setState(in.getCurrentStateName(), false);
|
c.setState(in.getCurrentStateName(), false);
|
||||||
|
|||||||
@@ -103,11 +103,14 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
// choices for constructor isPermanent argument
|
// choices for constructor isPermanent argument
|
||||||
private String originalDescription = "", description = "";
|
private String originalDescription = "", description = "";
|
||||||
private String originalStackDescription = "", stackDescription = "";
|
private String originalStackDescription = "", stackDescription = "";
|
||||||
private ManaCost multiKickerManaCost;
|
|
||||||
private Player activatingPlayer;
|
private Player activatingPlayer;
|
||||||
private Player targetingPlayer;
|
private Player targetingPlayer;
|
||||||
|
private Player choosingPlayer;
|
||||||
private Pair<Long, Player> controlledByPlayer;
|
private Pair<Long, Player> controlledByPlayer;
|
||||||
|
|
||||||
private ManaCostBeingPaid manaCostBeingPaid;
|
private ManaCostBeingPaid manaCostBeingPaid;
|
||||||
|
private ManaCost multiKickerManaCost;
|
||||||
private int spentPhyrexian = 0;
|
private int spentPhyrexian = 0;
|
||||||
private int paidLifeAmount = 0;
|
private int paidLifeAmount = 0;
|
||||||
|
|
||||||
@@ -147,7 +150,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
private TreeBasedTable<String, Boolean, CardCollection> paidLists = TreeBasedTable.create();
|
private TreeBasedTable<String, Boolean, CardCollection> paidLists = TreeBasedTable.create();
|
||||||
|
|
||||||
private EnumMap<AbilityKey, Object> triggeringObjects = AbilityKey.newMap();
|
private EnumMap<AbilityKey, Object> triggeringObjects = AbilityKey.newMap();
|
||||||
|
|
||||||
private EnumMap<AbilityKey, Object> replacingObjects = AbilityKey.newMap();
|
private EnumMap<AbilityKey, Object> replacingObjects = AbilityKey.newMap();
|
||||||
|
|
||||||
private final List<String> pipsToReduce = new ArrayList<>();
|
private final List<String> pipsToReduce = new ArrayList<>();
|
||||||
@@ -481,6 +483,13 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
targetingPlayer = targetingPlayer0;
|
targetingPlayer = targetingPlayer0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Player getChoosingPlayer() {
|
||||||
|
return choosingPlayer;
|
||||||
|
}
|
||||||
|
public void setChoosingPlayer(Player choosingPlayer0) {
|
||||||
|
choosingPlayer = choosingPlayer0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return returns who controls the controller of this sa when it is resolving (for Word of Command effect). Null means not being controlled by other
|
* @return returns who controls the controller of this sa when it is resolving (for Word of Command effect). Null means not being controlled by other
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ ManaCost:2 B B
|
|||||||
Types:Sorcery
|
Types:Sorcery
|
||||||
A:SP$ Charm | Cost$ 2 B B | Chooser$ Opponent | Choices$ DrawThree,DestroyAndDraw
|
A:SP$ Charm | Cost$ 2 B B | Chooser$ Opponent | Choices$ DrawThree,DestroyAndDraw
|
||||||
SVar:DrawThree:DB$ Draw | NumCards$ 3 | Defined$ You | SpellDescription$ You draw three cards.
|
SVar:DrawThree:DB$ Draw | NumCards$ 3 | Defined$ You | SpellDescription$ You draw three cards.
|
||||||
SVar:DestroyAndDraw:DB$ Destroy | ValidTgts$ Creature.ChosenCtrl | TgtPrompt$ Select target creature | TargetMin$ 0 | TargetMax$ 2 | NoRegen$ True | SpellDescription$ You destroy up to two target creatures that opponent controls and that player draws up to three cards. Those creatures can't be regenerated. | SubAbility$ ChooserDraws
|
SVar:DestroyAndDraw:DB$ Destroy | ValidTgts$ Creature.ControlledBy ChoosingPlayer | TgtPrompt$ Select target creature | TargetMin$ 0 | TargetMax$ 2 | NoRegen$ True | SpellDescription$ You destroy up to two target creatures that opponent controls and that player draws up to three cards. Those creatures can't be regenerated. | SubAbility$ ChooserDraws
|
||||||
SVar:ChooserDraws:DB$ Draw | NumCards$ 3 | Defined$ ChosenPlayer | UpTo$ True
|
SVar:ChooserDraws:DB$ Draw | NumCards$ 3 | Defined$ ChoosingPlayer | UpTo$ True
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
Oracle:An opponent chooses one —\n• You draw three cards.\n• You destroy up to two target creatures that player controls. They can't be regenerated. That player draws up to three cards.
|
Oracle:An opponent chooses one —\n• You draw three cards.\n• You destroy up to two target creatures that player controls. They can't be regenerated. That player draws up to three cards.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Types:Sorcery
|
|||||||
A:SP$ Charm | Cost$ 1 B R G | Chooser$ Opponent | Choices$ Fortune,Misfortune
|
A:SP$ Charm | Cost$ 1 B R G | Chooser$ Opponent | Choices$ Fortune,Misfortune
|
||||||
SVar:Fortune:DB$ PutCounterAll | ValidCards$ Creature.YouCtrl | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBGainLife | SpellDescription$ Put a +1/+1 counter on each creature you control. You gain 4 life. | SubAbility$ DBGainLife
|
SVar:Fortune:DB$ PutCounterAll | ValidCards$ Creature.YouCtrl | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBGainLife | SpellDescription$ Put a +1/+1 counter on each creature you control. You gain 4 life. | SubAbility$ DBGainLife
|
||||||
SVar:DBGainLife:DB$ GainLife | LifeAmount$ 4
|
SVar:DBGainLife:DB$ GainLife | LifeAmount$ 4
|
||||||
SVar:Misfortune:DB$ PutCounterAll | ValidCards$ Creature.ChosenCtrl | CounterType$ M1M1 | CounterNum$ 1 | SubAbility$ DBLoseLife | SpellDescription$ You put a -1/-1 counter on each creature that player controls and CARDNAME deals 4 damage to that player. | SubAbility$ DBDamage
|
SVar:Misfortune:DB$ PutCounterAll | ValidCards$ Creature.ControlledBy ChoosingPlayer | CounterType$ M1M1 | CounterNum$ 1 | SubAbility$ DBLoseLife | SpellDescription$ You put a -1/-1 counter on each creature that player controls and CARDNAME deals 4 damage to that player. | SubAbility$ DBDamage
|
||||||
SVar:DBDamage:DB$ DealDamage | Defined$ ChosenPlayer | NumDmg$ 4
|
SVar:DBDamage:DB$ DealDamage | Defined$ ChoosingPlayer | NumDmg$ 4
|
||||||
SVar:ChooserDraws:DB$ Draw | NumCards$ 3 | Defined$ ChosenPlayer
|
SVar:ChooserDraws:DB$ Draw | NumCards$ 3 | Defined$ ChosenPlayer
|
||||||
Oracle:An opponent chooses one —\n• You put a +1/+1 counter on each creature you control and gain 4 life.\n• You put a -1/-1 counter on each creature that player controls and Misfortune deals 4 damage to that player.
|
Oracle:An opponent chooses one —\n• You put a +1/+1 counter on each creature you control and gain 4 life.\n• You put a -1/-1 counter on each creature that player controls and Misfortune deals 4 damage to that player.
|
||||||
|
|||||||
@@ -74,11 +74,13 @@ public class HumanPlaySpellAbility {
|
|||||||
if ("X".equals(ability.getParam("CharmNum"))) {
|
if ("X".equals(ability.getParam("CharmNum"))) {
|
||||||
// CR 601.4
|
// CR 601.4
|
||||||
if (!announceValuesLikeX()) {
|
if (!announceValuesLikeX()) {
|
||||||
|
game.clearTopLibsCast(ability);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
needX = false;
|
needX = false;
|
||||||
}
|
}
|
||||||
if (!CharmEffect.makeChoices(ability)) {
|
if (!CharmEffect.makeChoices(ability)) {
|
||||||
|
game.clearTopLibsCast(ability);
|
||||||
// 603.3c If no mode is chosen, the ability is removed from the stack.
|
// 603.3c If no mode is chosen, the ability is removed from the stack.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user