Skip to content

Commit

Permalink
Fix AI applying cost raise twice (#6747)
Browse files Browse the repository at this point in the history
  • Loading branch information
tool4ever authored Jan 5, 2025
1 parent 2fcf95c commit e4247a2
Show file tree
Hide file tree
Showing 17 changed files with 47 additions and 56 deletions.
8 changes: 7 additions & 1 deletion forge-ai/src/main/java/forge/ai/ComputerUtilMana.java
Original file line number Diff line number Diff line change
Expand Up @@ -1280,7 +1280,13 @@ public static ManaCostBeingPaid calculateManaCost(final Cost cost, final SpellAb
card.setCastFrom(card.getZone() != null ? card.getZone() : null);
}

Cost payCosts = CostAdjustment.adjust(cost, sa, effect);
Cost payCosts;
if (test) {
payCosts = CostAdjustment.adjust(cost, sa, effect);
} else {
// when not testing CostPayment already handled raise
payCosts = cost;
}
CostPartMana manapart = payCosts != null ? payCosts.getCostMana() : null;
final ManaCost mana = payCosts != null ? ( manapart == null ? ManaCost.ZERO : manapart.getManaCostFor(sa) ) : ManaCost.NO_COST;

Expand Down
10 changes: 5 additions & 5 deletions forge-game/src/main/java/forge/game/Direction.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
public enum Direction {
Left,
Right;

private static final String LEFT = "Left";
private static final String RIGHT = "Right";
/** Immutable list of all directions (in order, Left and Right). */
Expand All @@ -36,15 +36,15 @@ public enum Direction {

/** @return The default direction. */
public static final Direction getDefaultDirection() { return Left; }

/** @return Immutable list of all directions (in order, Left and Right). */
public static List<Direction> getListOfDirections() { return listOfDirections; }

/** @return True if and only if this is the default direction. */
public boolean isDefaultDirection() {
return this.equals(getDefaultDirection());
}

/**
* Get the index by which the turn order is shifted, given this Direction.
* @return 1 or -1.
Expand All @@ -55,7 +55,7 @@ public int getShift() {
}
return -1;
}

/**
* Give the other Direction.
* @return Right if this is Left, and vice versa.
Expand Down
2 changes: 1 addition & 1 deletion forge-game/src/main/java/forge/game/Game.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ public class Game {
private Map<Player, Card> topLibsCast = Maps.newHashMap();
private Map<Card, Integer> facedownWhileCasting = Maps.newHashMap();

private Player monarch;
private Player initiative;
private Player monarch;
private Player monarchBeginTurn;
private Player startingPlayer;

Expand Down
8 changes: 0 additions & 8 deletions forge-game/src/main/java/forge/game/GameRules.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,31 +33,27 @@ public GameType getGameType() {
public boolean hasManaBurn() {
return manaBurn;
}

public void setManaBurn(final boolean manaBurn) {
this.manaBurn = manaBurn;
}

public boolean hasOrderCombatants() {
return orderCombatants;
}

public void setOrderCombatants(final boolean ordered) {
this.orderCombatants = ordered;
}

public int getPoisonCountersToLose() {
return poisonCountersToLose;
}

public void setPoisonCountersToLose(final int amount) {
this.poisonCountersToLose = amount;
}

public int getGamesPerMatch() {
return gamesPerMatch;
}

public void setGamesPerMatch(final int gamesPerMatch) {
this.gamesPerMatch = gamesPerMatch;
this.gamesToWinMatch = gamesPerMatch / 2 + 1;
Expand All @@ -66,31 +62,27 @@ public void setGamesPerMatch(final int gamesPerMatch) {
public boolean useAnte() {
return playForAnte;
}

public void setPlayForAnte(final boolean useAnte) {
this.playForAnte = useAnte;
}

public boolean getMatchAnteRarity() {
return matchAnteRarity;
}

public void setMatchAnteRarity(final boolean matchRarity) {
matchAnteRarity = matchRarity;
}

public boolean getSideboardForAI() {
return sideboardForAI;
}

public void setSideboardForAI(final boolean sideboard) {
sideboardForAI = sideboard;
}

public boolean getAISideboardingEnabled() {
return AISideboardingEnabled;
}

public void setAISideboardingEnabled(final boolean aiSideboarding) {
AISideboardingEnabled = aiSideboarding;
}
Expand Down
1 change: 0 additions & 1 deletion forge-game/src/main/java/forge/game/GameType.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ public enum GameType {
private final Function<RegisteredPlayer, Deck> deckAutoGenerator;

GameType(DeckFormat deckFormat0, boolean isCardPoolLimited0, boolean canSideboard0, boolean addWonCardsMidgame0, String name0, String description0) {

this(deckFormat0, isCardPoolLimited0, canSideboard0, addWonCardsMidgame0, name0, description0, null);
}
GameType(DeckFormat deckFormat0, boolean isCardPoolLimited0, boolean canSideboard0, boolean addWonCardsMidgame0, String name0, String description0, Function<RegisteredPlayer, Deck> deckAutoGenerator0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public void resolve(SpellAbility sa) {
// currently clean up in Card manually
altered = c.setSaddled(activate);
if (altered) {
CardCollection saddlers = (CardCollection) sa.getPaidList("TappedCards", true);
CardCollection saddlers = sa.getPaidList("TappedCards", true);
c.addSaddledByThisTurn(saddlers);
Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(c);
runParams.put(AbilityKey.Crew, saddlers);
Expand All @@ -72,15 +72,14 @@ public void resolve(SpellAbility sa) {
if (c.isCommander() == activate || p.getCommanders().contains(c) == activate)
break; //Isn't changing status.
if (activate) {
if(!c.getGame().getRules().hasCommander()) {
if (!c.getGame().getRules().hasCommander()) {
System.out.println("Commander status applied in non-commander format. Applying Commander variant.");
c.getGame().getRules().addAppliedVariant(GameType.Commander);
}
p.addCommander(c);
//Seems important enough to mention in the game log.
c.getGame().getGameLog().add(GameLogEntryType.STACK_RESOLVE, String.format("%s is now %s's commander.", c.getPaperCard().getName(), p));
}
else {
} else {
p.removeCommander(c);
c.getGame().getGameLog().add(GameLogEntryType.STACK_RESOLVE, String.format("%s is no longer %s's commander.", c.getPaperCard().getName(), p));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -678,8 +678,7 @@ private void changeKnownOriginResolve(final SpellAbility sa) {
}
if (sa.isKeyword(Keyword.UNEARTH) && movedCard.isInPlay()) {
movedCard.setUnearthed(true);
movedCard.addChangedCardKeywords(Lists.newArrayList("Haste"), null, false,
game.getNextTimestamp(), null, true);
movedCard.addChangedCardKeywords(Lists.newArrayList("Haste"), null, false, game.getNextTimestamp(), null);
registerDelayedTrigger(sa, "Exile", Lists.newArrayList(movedCard));
addLeaveBattlefieldReplacement(movedCard, sa, "Exile");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ public void resolve(SpellAbility sa) {
final List<CounterType> typeChoices = Lists.newArrayList();
// get types of counters
for (CounterType ct : tgtCounters.keySet()) {
if (dest.canReceiveCounters(ct) && source.canRemoveCounters(cType)) {
if (dest.canReceiveCounters(ct) && source.canRemoveCounters(ct)) {
typeChoices.add(ct);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public void resolve(SpellAbility sa) {
continue;
}

tgtC.addChangedCardKeywords(gainsKWList, null, false, timestamp, null, true);
tgtC.addChangedCardKeywords(gainsKWList, null, false, timestamp, null);
game.fireEvent(new GameEventCardStatsChanged(tgtC));

if (!"Permanent".equals(sa.getParam("Duration"))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ private static void applyPump(final SpellAbility sa, final Card applyTo,
gameCard.addPerpetual(params);
}
gameCard.addChangedCardKeywords(kws, Lists.newArrayList(), false, timestamp, null);

}
if (!hiddenKws.isEmpty()) {
gameCard.addHiddenExtrinsicKeywords(timestamp, 0, hiddenKws);
Expand Down
30 changes: 14 additions & 16 deletions forge-game/src/main/java/forge/game/card/Card.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
private Zone castFrom;
private SpellAbility castSA;

private CardDamageHistory damageHistory = new CardDamageHistory();
// Hidden keywords won't be displayed on the card
// x=timestamp y=StaticAbility id
private final Table<Long, Long, List<String>> hiddenExtrinsicKeywords = TreeBasedTable.create();
Expand Down Expand Up @@ -201,6 +200,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
private boolean monstrous;
private boolean renowned;
private boolean solved;
private boolean tributed;
private Long suspectedTimestamp = null;
private StaticAbility suspectedStatic = null;

Expand All @@ -227,12 +227,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
private boolean visitedThisTurn = false;

private int classLevel = 1;
private long bestowTimestamp = -1;
private long transformedTimestamp = 0;
private long prototypeTimestamp = -1;
private long mutatedTimestamp = -1;
private int timesMutated = 0;
private boolean tributed = false;

private boolean discarded, surveilled, milled;

Expand All @@ -254,6 +248,12 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
private int exertThisTurn = 0;
private PlayerCollection exertedByPlayer = new PlayerCollection();

private long bestowTimestamp = -1;
private long transformedTimestamp = 0;
private long prototypeTimestamp = -1;
private long mutatedTimestamp = -1;
private int timesMutated = 0;

private long gameTimestamp = -1; // permanents on the battlefield
private long layerTimestamp = -1;

Expand All @@ -264,6 +264,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
private Table<Long, Long, Pair<Integer,Integer>> newPT = TreeBasedTable.create(); // Layer 7b
private Table<Long, Long, Pair<Integer,Integer>> boostPT = TreeBasedTable.create(); // Layer 7c

private CardDamageHistory damageHistory = new CardDamageHistory();
private final Map<Card, Integer> assignedDamageMap = Maps.newTreeMap();
private Map<Integer, Integer> damage = Maps.newHashMap();
private boolean hasBeenDealtDeathtouchDamage;
Expand Down Expand Up @@ -358,7 +359,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
private ReplacementEffect shieldCounterReplaceDamage = null;
private ReplacementEffect shieldCounterReplaceDestroy = null;
private ReplacementEffect stunCounterReplaceUntap = null;
private ReplacementEffect finalityReplaceDying = null;
private ReplacementEffect finalityCounterReplaceDying = null;

// Enumeration for CMC request types
public enum SplitCMCMode {
Expand Down Expand Up @@ -4245,12 +4246,9 @@ public Iterable<CardColor> getChangedCardColors() {
public final void addChangedCardTypesByText(final CardType addType, final long timestamp, final long staticId) {
addChangedCardTypesByText(addType, timestamp, staticId, true);
}

public final void addChangedCardTypesByText(final CardType addType, final long timestamp, final long staticId, final boolean updateView) {
changedCardTypesByText.put(timestamp, staticId, new CardChangedType(addType, null, false,
EnumSet.of(RemoveType.SuperTypes,
RemoveType.CardTypes,
RemoveType.SubTypes)));
EnumSet.of(RemoveType.SuperTypes, RemoveType.CardTypes, RemoveType.SubTypes)));

// setting card type via text, does overwrite any other word change effects?
this.changedTextColors.addEmpty(timestamp, staticId);
Expand Down Expand Up @@ -7164,15 +7162,15 @@ public void updateReplacementEffects(List<ReplacementEffect> list, CardState sta
list.add(stunCounterReplaceUntap);
}
if (getCounters(CounterEnumType.FINALITY) > 0) {
if (finalityReplaceDying == null) {
if (finalityCounterReplaceDying == null) {
String reStr = "Event$ Moved | ActiveZones$ Battlefield | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Secondary$ True "
+ " | Description$ If CARDNAME would die, exile it instead.";
String sa = "DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | Defined$ ReplacedCard";

finalityReplaceDying = ReplacementHandler.parseReplacement(reStr, this, false, null);
finalityReplaceDying.setOverridingAbility(AbilityFactory.getAbility(sa, this));
finalityCounterReplaceDying = ReplacementHandler.parseReplacement(reStr, this, false, null);
finalityCounterReplaceDying.setOverridingAbility(AbilityFactory.getAbility(sa, this));
}
list.add(finalityReplaceDying);
list.add(finalityCounterReplaceDying);
}
}

Expand Down
12 changes: 6 additions & 6 deletions forge-game/src/main/java/forge/game/card/CardState.java
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,12 @@ public final boolean addIntrinsicKeywords(final Iterable<String> keywords, boole
return changed;
}

public void addIntrinsicKeywords(Collection<KeywordInterface> intrinsicKeywords2) {
for (KeywordInterface inst : intrinsicKeywords2) {
intrinsicKeywords.insert(inst);
}
}

public final boolean removeIntrinsicKeyword(final String s) {
return intrinsicKeywords.remove(s);
}
Expand Down Expand Up @@ -758,12 +764,6 @@ public boolean hasProperty(String property, Player sourceController, Card source
return ForgeScript.cardStateHasProperty(this, property, sourceController, source, spellAbility);
}

public void addIntrinsicKeywords(Collection<KeywordInterface> intrinsicKeywords2) {
for (KeywordInterface inst : intrinsicKeywords2) {
intrinsicKeywords.insert(inst);
}
}

public ImmutableList<CardTraitBase> getTraits() {
return ImmutableList.<CardTraitBase>builder()
.addAll(manaAbilities)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ public boolean insert(KeywordInterface inst) {
return true;
}
return false;

}

public void addAll(Iterable<String> keywords) {
Expand Down
4 changes: 2 additions & 2 deletions forge-game/src/main/java/forge/game/player/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ public class Player extends GameEntity implements Comparable<Player> {
private int expentThisTurn;
private int numLibrarySearchedOwn; //The number of times this player has searched his library
private int venturedThisTurn;
private int descended = 0;
private int descended;
private int numRingTemptedYou;
private boolean revolt = false;
private int numRingTemptedYou = 0;
private Card ringBearer, theRing;

private List<Card> discardedThisTurn = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ public static boolean cantTarget(final Player player, final SpellAbility spellAb
* the spell/ability
* @return true, if successful
*/
public static boolean applyCantTargetAbility(final StaticAbility stAb, final Card card,
final SpellAbility spellAbility) {
public static boolean applyCantTargetAbility(final StaticAbility stAb, final Card card, final SpellAbility spellAbility) {
if (stAb.hasParam("ValidPlayer")) {
return false;
}
Expand Down
3 changes: 2 additions & 1 deletion forge-game/src/main/java/forge/game/zone/MagicStack.java
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ public final void add(SpellAbility sp, SpellAbilityStackInstance si, int id) {
// Copied abilities aren't activated, so they shouldn't change these values
addAbilityActivatedThisTurn(sp, source);
}

Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(source.getController());
runParams.put(AbilityKey.Cost, sp.getPayCosts());
runParams.put(AbilityKey.Activator, activator);
Expand All @@ -281,7 +282,7 @@ public final void add(SpellAbility sp, SpellAbilityStackInstance si, int id) {
runParams2.put(AbilityKey.SpellAbility, sp);
game.getTriggerHandler().runTrigger(TriggerType.AbilityResolves, runParams2, false);

game.getGameLog().add(GameLogEntryType.MANA, source + " - " + sp.getDescription());
game.getGameLog().add(GameLogEntryType.MANA, source + " - " + sp);
sp.resetOnceResolved();
return;
}
Expand Down
6 changes: 3 additions & 3 deletions forge-gui/res/cardsfolder/f/from_the_catacombs.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
Name:From the Catacombs
ManaCost:3 B B
Types:Sorcery
A:SP$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | GainControl$ True | TgtPrompt$ Select target creature card in a graveyard | ValidTgts$ Creature | WithCountersType$ CORPSE | LeaveBattlefield$ Exile | SubAbility$ DBInitiative | SpellDescription$ Put target creature card from a graveyard onto the battlefield under your control with a corpse counter on it. If that creature would leave the battlefield, exile it instead of putting it anywhere else.
SVar:DBInitiative:DB$ TakeInitiative | SpellDescription$ You take the initiative.
A:SP$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | GainControl$ True | TgtPrompt$ Select target creature card in a graveyard | ValidTgts$ Creature | WithCountersType$ CORPSE | LeaveBattlefield$ Exile | SubAbility$ DBInitiative | SpellDescription$ Put target creature card from a graveyard onto the battlefield under your control with a corpse counter on it. You take the initiative. If that creature would leave the battlefield, exile it instead of putting it anywhere else.
SVar:DBInitiative:DB$ TakeInitiative
K:Escape:3 B B ExileFromGrave<5/Card.Other/other>
DeckHas:Ability$Graveyard
DeckHints:Ability$Discard
Oracle:Put target creature card from a graveyard onto the battlefield under your control with a corpse counter on it. If that creature would leave the battlefield, exile it instead of putting it anywhere else.\nYou take the initiative.\nEscape—{3}{B}{B}, Exile five other cards from your graveyard. (You may cast this card from your graveyard for its escape cost.)
Oracle:Put target creature card from a graveyard onto the battlefield under your control with a corpse counter on it. You take the initiative. If that creature would leave the battlefield, exile it instead of putting it anywhere else.\nEscape—{3}{B}{B}, Exile five other cards from your graveyard. (You may cast this card from your graveyard for its escape cost.)

0 comments on commit e4247a2

Please sign in to comment.