Skip to content

Commit

Permalink
Timestamp checks rebased
Browse files Browse the repository at this point in the history
  • Loading branch information
tool4ever authored and tool4EvEr committed Jan 20, 2025
1 parent 44a1073 commit 9720069
Show file tree
Hide file tree
Showing 47 changed files with 324 additions and 243 deletions.
15 changes: 7 additions & 8 deletions forge-ai/src/main/java/forge/ai/ability/UntapAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -319,15 +319,14 @@ private boolean untapTargetList(final Card source, final TargetRestrictions tgt,

@Override
public Card chooseSingleCard(Player ai, SpellAbility sa, Iterable<Card> list, boolean isOptional, Player targetedPlayer, Map<String, Object> params) {
CardCollection pref = CardLists.filterControlledBy(list, ai.getYourTeam());
if (pref.isEmpty()) {
if (isOptional) {
return null;
}
} else {
list = pref;
CardCollection filteredList = CardLists.filterControlledBy(list, ai.getYourTeam());
if (!filteredList.isEmpty()) {
return ComputerUtilCard.getBestAI(filteredList);
}
if (isOptional) {
return null;
}
return ComputerUtilCard.getBestAI(list);
return ComputerUtilCard.getWorstAI(list);
}

private static Card detectPriorityUntapTargets(final List<Card> untapList) {
Expand Down
2 changes: 1 addition & 1 deletion forge-game/src/main/java/forge/game/GameActionUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,6 @@ public static SpellAbility addExtraKeywordCost(final SpellAbility sa) {

if (v > 0) {
Card eff = createETBCountersEffect(c, host, activator, "P1P1", String.valueOf(v));

if (result == null) {
result = sa.copy();
}
Expand Down Expand Up @@ -725,6 +724,7 @@ public static SpellAbility addExtraKeywordCost(final SpellAbility sa) {
public static Card createETBCountersEffect(Card sourceCard, Card c, Player controller, String counter, String amount) {
final Game game = sourceCard.getGame();
final Card eff = new Card(game.nextCardId(), game);

eff.setGameTimestamp(game.getNextTimestamp());
eff.setName(sourceCard + "'s Effect");
eff.setOwner(controller);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ protected String getStackDescription(SpellAbility sa) {
@Override
public void resolve(SpellAbility sa) {
final Game game = sa.getActivatingPlayer().getGame();
if (game.getCombat() == null) {
return;
}
List<Card> blocked = Lists.newArrayList();
for (final Card c : getTargetCards(sa)) {
game.getCombat().setBlocked(c, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import forge.game.card.CardPredicates;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.player.PlayerCollection;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
Expand Down Expand Up @@ -60,7 +61,7 @@ public void resolve(SpellAbility sa) {
final Game game = activator.getGame();
CardCollection allChosen = new CardCollection();

final List<Player> tgtPlayers = getDefinedPlayersOrTargeted(sa);
final PlayerCollection tgtPlayers = getDefinedPlayersOrTargeted(sa);

List<ZoneType> choiceZone = Lists.newArrayList(ZoneType.Battlefield);
if (sa.hasParam("ChoiceZone")) {
Expand All @@ -71,7 +72,7 @@ public void resolve(SpellAbility sa) {
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, host, sa);
}
if (sa.hasParam("TargetControls")) {
choices = CardLists.filterControlledBy(choices, tgtPlayers.get(0));
choices = CardLists.filterControlledBy(choices, tgtPlayers);
}
if (sa.hasParam("DefinedCards")) {
choices = AbilityUtils.getDefinedCards(host, sa.getParam("DefinedCards"), sa);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ protected String getStackDescription(SpellAbility sa) {

sb.append(Lang.joinHomogenous(getTargetPlayers(sa)));

sb.append("chooses a player.");
sb.append(" chooses a player.");

return sb.toString();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package forge.game.ability.effects;

import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -152,7 +151,7 @@ public void resolve(SpellAbility sa) {
}
}
} else {
throw new InvalidParameterException(sa.getHostCard() + "'s ability resulted in no types to choose from");
throw new RuntimeException(sa.getHostCard() + "'s ability resulted in no types to choose from");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,13 @@ public void resolve(SpellAbility sa) {
}
}

CardCollectionView srcCards = null;
CardCollectionView srcCards;

String typeforPrompt = counterType == null ? "" : counterType.getName();
String title = Localizer.getInstance().getMessage("lblChooseCardsToTakeTargetCounters", typeforPrompt);
title = title.replace(" ", " ");
if (sa.hasParam("ValidSource")) {
srcCards = game.getCardsIn(ZoneType.Battlefield);
srcCards = CardLists.getValidCards(srcCards, sa.getParam("ValidSource"), activator, card, sa);
srcCards = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), sa.getParam("ValidSource"), activator, card, sa);
if (num.equals("Any")) {
Map<String, Object> params = Maps.newHashMap();
params.put("CounterType", counterType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,13 +255,10 @@ public void resolve(SpellAbility sa) {
if (o instanceof Card) {
final Card c = (Card) o;
final Card gc = game.getCardState(c, null);
if (gc == null || !c.equalsWithGameTimestamp(gc) || !gc.isInPlay()) {
if (gc == null || !c.equalsWithGameTimestamp(gc) || !gc.isInPlay() || gc.isPhasedOut()) {
// timestamp different or not in play
continue;
}
if (c.isPhasedOut()) {
continue;
}
internalDamageDeal(sa, sourceLKI, gc, dmg, damageMap);
} else if (o instanceof Player) {
final Player p = (Player) o;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,20 +93,29 @@ public void resolve(SpellAbility sa) {
}
}
}
} else for (final GameEntity ge : getTargetEntities(sa)) {
} else for (GameEntity ge : getTargetEntities(sa)) {
// check before checking sources
if (ge instanceof Card) {
final Card c = (Card) ge;
if (!c.isInPlay() || c.isPhasedOut()) {
continue;
}
// check if the object is still in game or if it was moved
Card gameCard = game.getCardState(c, null);
// gameCard is LKI in that case, the card is not in game anymore
// or the timestamp did change
// this should check Self too
if (gameCard == null || !c.equalsWithGameTimestamp(gameCard)) {
continue;
}
ge = gameCard;
}

for (final Card source : sources) {
final Card sourceLKI = game.getChangeZoneLKIInfo(source);

final int dmg = AbilityUtils.calculateAmount(source, num, sa);

if (ge instanceof Card) {
final Card c = (Card) ge;
if (c.isInPlay() && !c.isPhasedOut()) {
damageMap.put(sourceLKI, c, dmg);
}
} else {
damageMap.put(sourceLKI, ge, dmg);
}
damageMap.put(sourceLKI, ge, dmg);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,10 @@ public void resolve(SpellAbility sa) {

final List<String> addedKW = Lists.newArrayList();
final List<String> removedKW = Lists.newArrayList();

if (sa.hasParam("AllSuffixKeywords")) {
// this only for walk abilities, may to try better
if (sa.getParam("AllSuffixKeywords").equals("walk")) {
for (final KeywordInterface kw : tgtC.getKeywords(Keyword.LANDWALK)) {
for (final KeywordInterface kw : gameCard.getKeywords(Keyword.LANDWALK)) {
removedKW.add(kw.getOriginal());
}
}
Expand All @@ -109,7 +108,7 @@ public void resolve(SpellAbility sa) {
continue;
}
final String wardString = StringUtils.capitalize(colString) + ":" + colString;
for (final KeywordInterface inst : tgtC.getKeywords(Keyword.PROTECTION)) {
for (final KeywordInterface inst : gameCard.getKeywords(Keyword.PROTECTION)) {
// special for the Ward Auras Protection:Card.<Color>:<color>:*
String keyword = inst.getOriginal();
if (keyword.startsWith("Protection:") && keyword.contains(wardString)) {
Expand All @@ -122,11 +121,12 @@ public void resolve(SpellAbility sa) {
if (ProtectionFromColor) {
// Split "Protection from each color" into extra Protection from <color>
String allColors = "Protection from each color";
if (tgtC.hasKeyword(allColors)) {
if (gameCard.hasKeyword(allColors)) {
final List<String> allColorsProtect = Lists.newArrayList();

for (byte col : MagicColor.WUBRG) {
allColorsProtect.add("Protection from " + MagicColor.toLongString(col));

}
allColorsProtect.removeAll(kws);
addedKW.addAll(allColorsProtect);
Expand All @@ -135,7 +135,7 @@ public void resolve(SpellAbility sa) {

// Extra for Spectra Ward
allColors = "Protection:Card.nonColorless:each color:Aura";
if (tgtC.hasKeyword(allColors)) {
if (gameCard.hasKeyword(allColors)) {
final List<String> allColorsProtect = Lists.newArrayList();

for (byte col : MagicColor.WUBRG) {
Expand All @@ -150,15 +150,15 @@ public void resolve(SpellAbility sa) {
}

removedKW.addAll(kws);
tgtC.addChangedCardKeywords(addedKW, removedKW, false, timestamp, null);
gameCard.addChangedCardKeywords(addedKW, removedKW, false, timestamp, null);

if (!"Permanent".equals(sa.getParam("Duration"))) {
final GameCommand until = new GameCommand() {
private static final long serialVersionUID = 5387486776282932314L;

@Override
public void run() {
tgtC.removeChangedCardKeywords(timestamp, 0);
gameCard.removeChangedCardKeywords(timestamp, 0);
}
};
addUntilCommand(sa, until);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,17 @@ public void resolve(SpellAbility sa) {
continue;
}

// check if the object is still in game or if it was moved
Card gameCard = game.getCardState(tgtC, null);
// gameCard is LKI in that case, the card is not in game anymore
// or the timestamp did change
// this should check Self too
if (gameCard == null || !tgtC.equalsWithGameTimestamp(gameCard)) {
continue;
}

// 701.38d is handled by getGoaded
tgtC.addGoad(timestamp, player);
gameCard.addGoad(timestamp, player);

// currently, only Life of the Party uses Duration$ – Duration$ Permanent
if (!duration.equals("Permanent")) {
Expand All @@ -56,14 +65,14 @@ public void resolve(SpellAbility sa) {

@Override
public void run() {
tgtC.removeGoad(timestamp);
gameCard.removeGoad(timestamp);
}
};

addUntilCommand(sa, until, duration, player);
}

if (remember && tgtC.isGoaded()) {
if (remember && gameCard.isGoaded()) {
sa.getHostCard().addRemembered(tgtC);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ public void resolve(SpellAbility sa) {
MutableBoolean combatChanged = new MutableBoolean(false);

for (final Player p : getTargetPlayers(sa)) {
if (!p.isInGame()) {
continue;
}
if (sa.hasParam("Optional") && !p.getController().confirmAction(sa, null,
Localizer.getInstance().getMessage("lblWouldYouLikeInvestigate"), null)) {
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ private static List<Integer> getDistribution(List<Player> players, boolean top,
// combination is valid, check next
PlayerCollection nextPlayers = new PlayerCollection(players);
nextPlayers.remove(p);
List<Integer> nextChoices = new ArrayList<>(remainingChoices);
List<Integer> nextChoices = Lists.newArrayList(remainingChoices);
nextChoices.remove(choice);
nextChoices = getDistribution(nextPlayers, false, nextChoices);
if (nextChoices.isEmpty()) {
Expand All @@ -131,7 +131,7 @@ private static List<Integer> getDistribution(List<Player> players, boolean top,
return validChoices;
}
}
return new ArrayList<>();
return Lists.newArrayList();
}

/* (non-Javadoc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,33 @@ protected void manifestLoop(SpellAbility sa, Player p, final int amount) {

if (fromLibrary) {
for (Card c : tgtCards) {
Card gameCard = game.getCardState(c, null);
// gameCard is LKI in that case, the card is not in game anymore
// or the timestamp did change
// this should check Self too
if (gameCard == null || !c.equalsWithGameTimestamp(gameCard)) {
continue;
}

// CR 701.34d If an effect instructs a player to manifest multiple cards from their library, those cards are manifested one at a time.
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
CardZoneTable triggerList = AbilityKey.addCardZoneTableParams(moveParams, sa);
internalEffect(c, p, sa, moveParams);
internalEffect(gameCard, p, sa, moveParams);
triggerList.triggerChangesZoneAll(game, sa);
}
} else {
// manifest from other zones should be done at the same time
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
CardZoneTable triggerList = AbilityKey.addCardZoneTableParams(moveParams, sa);
for (Card c : tgtCards) {
internalEffect(c, p, sa, moveParams);
Card gameCard = game.getCardState(c, null);
// gameCard is LKI in that case, the card is not in game anymore
// or the timestamp did change
// this should check Self too
if (gameCard == null || !c.equalsWithGameTimestamp(gameCard)) {
continue;
}
internalEffect(gameCard, p, sa, moveParams);
}
triggerList.triggerChangesZoneAll(game, sa);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,30 +72,44 @@ public void resolve(SpellAbility sa) {
toPhase.add(tgtC);
}
for (final Card tgtC : toPhase) {
tgtC.phase(false);
if (tgtC.isPhasedOut()) {
phasedOut.add(tgtC);
tgtC.setWontPhaseInNormal(wontPhaseInNormal);
Card gameCard = game.getCardState(tgtC, null);
// gameCard is LKI in that case, the card is not in game anymore
// or the timestamp did change
// this should check Self too
if (gameCard == null || !tgtC.equalsWithGameTimestamp(gameCard)) {
continue;
}
gameCard.phase(false);
if (gameCard.isPhasedOut()) {
phasedOut.add(gameCard);
gameCard.setWontPhaseInNormal(wontPhaseInNormal);
} else {
// won't trigger tap or untap triggers when phase in
if (sa.hasParam("Tapped")) {
tgtC.setTapped(true);
gameCard.setTapped(true);
} else if (sa.hasParam("Untapped")) {
tgtC.setTapped(false);
gameCard.setTapped(false);
}
tgtC.setWontPhaseInNormal(false);
gameCard.setWontPhaseInNormal(false);
}
}
} else { // just phase out
for (final Card tgtC : tgtCards) {
if (!tgtC.isPhasedOut() && !StaticAbilityCantPhase.cantPhaseOut(tgtC)) {
tgtC.phase(false);
if (tgtC.isPhasedOut()) {
Card gameCard = game.getCardState(tgtC, null);
// gameCard is LKI in that case, the card is not in game anymore
// or the timestamp did change
// this should check Self too
if (gameCard == null || !tgtC.equalsWithGameTimestamp(gameCard)) {
continue;
}
if (!gameCard.isPhasedOut() && !StaticAbilityCantPhase.cantPhaseOut(gameCard)) {
gameCard.phase(false);
if (gameCard.isPhasedOut()) {
if (sa.hasParam("RememberAffected")) {
source.addRemembered(tgtC);
source.addRemembered(gameCard);
}
phasedOut.add(tgtC);
tgtC.setWontPhaseInNormal(wontPhaseInNormal);
phasedOut.add(gameCard);
gameCard.setWontPhaseInNormal(wontPhaseInNormal);
}
}
}
Expand Down
Loading

0 comments on commit 9720069

Please sign in to comment.