Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix AI applying cost raise twice #6747

Merged
merged 1 commit into from
Jan 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -677,8 +677,7 @@ private void changeKnownOriginResolve(final SpellAbility sa) {
}
if (sa.hasParam("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 @@ -357,7 +358,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 @@ -4228,12 +4229,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 @@ -7146,15 +7144,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.)
Loading