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

Convoke improvise delve #6646

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
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
31 changes: 30 additions & 1 deletion forge-ai/src/main/java/forge/ai/ComputerUtilMana.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import forge.game.card.*;
import forge.game.combat.CombatUtil;
import forge.game.cost.*;
import forge.game.keyword.Keyword;
import forge.game.mana.Mana;
import forge.game.mana.ManaCostBeingPaid;
import forge.game.mana.ManaPool;
Expand Down Expand Up @@ -1420,7 +1421,7 @@ public static ManaCostBeingPaid calculateManaCost(final SpellAbility sa, final b
}
}

CostAdjustment.adjust(cost, sa, null, test);
CostAdjustment.adjust(cost, sa, test);

int timesMultikicked = card.getKickerMagnitude();
if (timesMultikicked > 0 && sa.hasParam("Announce") && sa.getParam("Announce").startsWith("Multikicker")) {
Expand Down Expand Up @@ -1806,6 +1807,34 @@ public static List<SpellAbility> getAIPlayableMana(Card c) {
return res;
}

// Convoke, Delve, Improvise
public static List<SpellAbility> getAIPlayableSpecialAbilities(Card card, Player ai, SpellAbility saPaidFor, ManaCostBeingPaid manaCost) {
List<SpellAbility> result = new ArrayList<>();
if (saPaidFor.isSpell()) {
Collection<SpellAbility> specialAbilities = Lists.newArrayList();
if (card.isInPlay() && card.isUntapped()) {
if (saPaidFor.getHostCard().hasKeyword(Keyword.CONVOKE) && card.isCreature()) {
specialAbilities.addAll(CardFactoryUtil.buildConvokeAbility(card, manaCost, saPaidFor));
}

if (saPaidFor.getHostCard().hasKeyword(Keyword.IMPROVISE) && card.isArtifact()) {
specialAbilities.add(CardFactoryUtil.buildImproviseAbility(card, manaCost, saPaidFor));
}
}
if (card.isInZone(ZoneType.Graveyard)) {
if (saPaidFor.getHostCard().hasKeyword(Keyword.DELVE)) {
specialAbilities.add(CardFactoryUtil.buildDelveAbility(card, manaCost, saPaidFor));
}
}
// set the activating player
for (final SpellAbility sa : specialAbilities) {
sa.setActivatingPlayer(ai);
result.add(sa);
}
}
return result;
}

private static void handleOfferingsAI(final SpellAbility sa, boolean test, boolean costIsPaid) {
if (sa.isOffering() && sa.getSacrificedAsOffering() != null) {
final Card offering = sa.getSacrificedAsOffering();
Expand Down
2 changes: 1 addition & 1 deletion forge-core/src/main/java/forge/token/TokenDb.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public void preloadTokens() {

@Override
public PaperToken getToken(String tokenName, String edition) {
String fullName = String.format("%s_%s", tokenName, edition.toLowerCase());
String fullName = String.format("%s_%s", tokenName, edition.toLowerCase(Locale.ENGLISH));

if (!tokensByName.containsKey(fullName)) {
try {
Expand Down
4 changes: 0 additions & 4 deletions forge-game/src/main/java/forge/game/GameAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,6 @@ private Card changeZone(final Zone zoneFrom, Zone zoneTo, final Card c, Integer
}

copied.clearDevoured();
copied.clearDelved();
copied.clearConvoked();
copied.clearExploited();
}

Expand Down Expand Up @@ -512,8 +510,6 @@ private Card changeZone(final Zone zoneFrom, Zone zoneTo, final Card c, Integer

if (!c.isRealToken() && !toBattlefield) {
copied.clearDevoured();
copied.clearDelved();
copied.clearConvoked();
copied.clearExploited();
}

Expand Down
47 changes: 19 additions & 28 deletions forge-game/src/main/java/forge/game/card/Card.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
private final KeywordCollection hiddenExtrinsicKeyword = new KeywordCollection();

// cards attached or otherwise linked to this card
private CardCollection hauntedBy, devouredCards, exploitedCards, delvedCards, convokedCards, imprintedCards, encodedCards;
private CardCollection hauntedBy, devouredCards, exploitedCards, imprintedCards, encodedCards;
private CardCollection mustBlockCards, gainControlTargets, chosenCards, blockedThisTurn, blockedByThisTurn;
private CardCollection mergedCards;

Expand Down Expand Up @@ -913,31 +913,17 @@ public final void clearExploited() {
}

public final CardCollectionView getDelved() {
return CardCollection.getView(delvedCards);
}
public final void addDelved(final Card c) {
if (delvedCards == null) {
delvedCards = new CardCollection();
if (getCastSA() == null) {
return CardCollection.EMPTY;
}
delvedCards.add(c);
}

public final void clearDelved() {
delvedCards = null;
return getCastSA().getDelved();
}


public final CardCollectionView getConvoked() {
return CardCollection.getView(convokedCards);
}
public final void addConvoked(final Card c) {
if (convokedCards == null) {
convokedCards = new CardCollection();
if (getCastSA() == null) {
return CardCollection.EMPTY;
}
convokedCards.add(c);
}
public final void clearConvoked() {
convokedCards = null;
return getCastSA().getTappedForConvoke();
}

public MapOfLists<GameEntity, Object> getRememberMap() {
Expand Down Expand Up @@ -1136,7 +1122,7 @@ public final void moveMergedToSubgame(SpellAbility cause) {
newTop = c;
}
}

if (newTop != null) {
removeMutatedStates();
newTop.mergedCards = mergedCards;
Expand Down Expand Up @@ -5474,7 +5460,7 @@ protected void resetExtertedThisTurn() {
}

public boolean isMadness() {
if (this.getCastSA() == null) {
if (getCastSA() == null) {
return false;
}
return getCastSA().isMadness();
Expand Down Expand Up @@ -5509,12 +5495,12 @@ public final void setManifested(final boolean manifested) {

public final boolean isForetold() {
// in exile and foretold
if (this.isInZone(ZoneType.Exile)) {
return this.foretold;
if (isInZone(ZoneType.Exile)) {
return foretold;
}
// cast as foretold, currently only spells
if (this.getCastSA() != null) {
return this.getCastSA().isForetold();
if (getCastSA() != null) {
return getCastSA().isForetold();
}
return false;
}
Expand Down Expand Up @@ -6248,10 +6234,15 @@ public final boolean canBeSacrificedBy(final SpellAbility source) {
return false;
}

if (source == null){
if (source == null) {
return true;
}

// can't sacrifice it for mana ability if it is already marked as sacrifice
if (source.isManaAbility() && isUsedToPay()) {
return false;
}

if (isCreature() && source.getActivatingPlayer().hasKeyword("You can't sacrifice creatures to cast spells or activate abilities.")) {
Cost srcCost = source.getPayCosts();
if (srcCost != null) {
Expand Down
150 changes: 150 additions & 0 deletions forge-game/src/main/java/forge/game/card/CardFactoryUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import forge.game.cost.Cost;
import forge.game.keyword.Keyword;
import forge.game.keyword.KeywordInterface;
import forge.game.mana.ManaCostBeingPaid;
import forge.game.phase.PhaseHandler;
import forge.game.player.Player;
import forge.game.player.PlayerCollection;
Expand All @@ -51,6 +52,7 @@
import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerHandler;
import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.Expressions;
Expand Down Expand Up @@ -4991,4 +4993,152 @@ public static void setupAdventureAbility(Card card) {
re.setOverridingAbility(saExile);
card.addReplacementEffect(re);
}

public static SpellAbility buildConvokeAbility(final Card host, final ManaCostShard shard, final ManaCostBeingPaid manaCost, final SpellAbility saPaidFor) {
SpellAbility result = new AbilityStatic(host, Cost.Zero, null) {

@Override
public boolean isConvoke() {
return true;
}

@Override
public boolean isManaAbility() {
return true;
}

public boolean canPlay() {
if (getHostCard().isTapped()) {
return false;
}
if (!manaCost.canDecreaseShard(shard)) {
return false;
}

return super.canPlay();
}

@Override
public boolean undo() {
saPaidFor.removeTappedForConvoke(host);
host.setTapped(false);
manaCost.increaseShard(shard, 1);
return true;
}

@Override
public void resolve() {
host.getGame().getTriggerHandler().suppressMode(TriggerType.Taps);
saPaidFor.addTappedForConvoke(host);
host.setTapped(false);
host.tap();
manaCost.decreaseShard(shard, 1);
host.getGame().getTriggerHandler().clearSuppression(TriggerType.Taps);
}

};
result.setDescription("Convoke " + shard.toString());
result.setUndoable(true);
return result;
}

public static Collection<SpellAbility> buildConvokeAbility(final Card host, final ManaCostBeingPaid manaCost, final SpellAbility saPaidFor) {
List<SpellAbility> result = Lists.newArrayList();
for (byte color : host.determineColor()) {
result.add(buildConvokeAbility(host, ManaCostShard.valueOf(color), manaCost, saPaidFor));
}
result.add(buildConvokeAbility(host, ManaCostShard.GENERIC, manaCost, saPaidFor));
return result;
}

public static SpellAbility buildImproviseAbility(final Card host, final ManaCostBeingPaid manaCost, final SpellAbility saPaidFor) {
SpellAbility result = new AbilityStatic(host, Cost.Zero, null) {

@Override
public boolean isImprovise() {
return true;
}

@Override
public boolean isManaAbility() {
return true;
}

public boolean canPlay() {
if (getHostCard().isTapped()) {
return false;
}
if (!manaCost.canDecreaseShard(ManaCostShard.GENERIC)) {
return false;
}

return super.canPlay();
}

@Override
public boolean undo() {
saPaidFor.removeTappedForImprovise(host);
host.setTapped(false);
manaCost.increaseGenericMana(1);
return true;
}

@Override
public void resolve() {
host.getGame().getTriggerHandler().suppressMode(TriggerType.Taps);
saPaidFor.addTappedForImprovise(host);
host.setTapped(false);
host.tap();
manaCost.decreaseGenericMana(1);
host.getGame().getTriggerHandler().clearSuppression(TriggerType.Taps);
}

};
result.setDescription("Improvise");
result.setUndoable(true);
return result;
}

public static SpellAbility buildDelveAbility(final Card host, final ManaCostBeingPaid manaCost, final SpellAbility saPaidFor) {
SpellAbility result = new AbilityStatic(host, Cost.Zero, null) {

@Override
public boolean isDelve() {
return true;
}

@Override
public boolean isManaAbility() {
return true;
}

public boolean canPlay() {
if (saPaidFor.getDelved().contains(host)) {
return false;
}
if (!manaCost.canDecreaseShard(ManaCostShard.GENERIC)) {
return false;
}

return super.canPlay();
}

@Override
public boolean undo() {
saPaidFor.removeDelved(host);
manaCost.increaseGenericMana(1);
return true;
}

@Override
public void resolve() {
saPaidFor.addDelved(host);
manaCost.decreaseGenericMana(1);
}

};
result.setDescription("Delve");
result.setUndoable(true);
return result;
}
}
Loading