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

Card: add Table for SwitchPT #3556

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
5 changes: 5 additions & 0 deletions forge-ai/src/main/java/forge/ai/ComputerUtilCard.java
Original file line number Diff line number Diff line change
Expand Up @@ -1758,6 +1758,11 @@ public static Card getPumpedCreature(final Player ai, final SpellAbility sa,
pumped.setPTBoost(c.getPTBoostTable());
pumped.addPTBoost(power + berserkPower, toughness, timestamp, 0);

pumped.setSwitchPTTable(c.getSwitchPTTable());
if (sa.hasParam("SwitchPT")) {
pumped.addSwitchPT(timestamp, 0);
}

if (!kws.isEmpty()) {
pumped.addChangedCardKeywords(kws, null, false, timestamp, 0, false);
}
Expand Down
91 changes: 79 additions & 12 deletions forge-ai/src/main/java/forge/ai/ability/PumpAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
import com.google.common.collect.Maps;

import forge.ai.*;
import forge.game.CardTraitPredicates;
import forge.game.Game;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.*;
Expand All @@ -18,6 +20,9 @@
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementLayer;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
Expand Down Expand Up @@ -65,12 +70,6 @@ protected boolean checkAiLogic(final Player ai, final SpellAbility sa, final Str
return SpecialAiLogic.doAristocratLogic(ai, sa);
} else if (aiLogic.startsWith("AristocratCounters")) {
return SpecialAiLogic.doAristocratWithCountersLogic(ai, sa);
} else if (aiLogic.equals("SwitchPT")) {
// Some more AI would be even better, but this is a good start to prevent spamming
if (sa.isActivatedAbility() && sa.getActivationsThisTurn() > 0 && !sa.usesTargeting()) {
// Will prevent flipping back and forth
return false;
}
}

return super.checkAiLogic(ai, sa, aiLogic);
Expand All @@ -91,11 +90,6 @@ protected boolean checkPhaseRestrictions(final Player ai, final SpellAbility sa,
if (!ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS) && !isThreatened) {
return false;
}
} else if (logic.equals("SwitchPT")) {
// Some more AI would be even better, but this is a good start to prevent spamming
if (ph.getPhase().isAfter(PhaseType.COMBAT_FIRST_STRIKE_DAMAGE) || !ph.inCombat()) {
return false;
}
}
return super.checkPhaseRestrictions(ai, sa, ph);
}
Expand All @@ -112,6 +106,12 @@ protected boolean checkPhaseRestrictions(final Player ai, final SpellAbility sa,
return false;
}
}
if (sa.hasParam("SwitchPT")) {
// Some more AI would be even better, but this is a good start to prevent spamming
if (ph.getPhase().isAfter(PhaseType.COMBAT_FIRST_STRIKE_DAMAGE) || !ph.inCombat()) {
return false;
}
}
if (game.getStack().isEmpty() && (ph.getPhase().isBefore(PhaseType.COMBAT_BEGIN)
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS))) {
// Instant-speed pumps should not be cast outside of combat when the
Expand Down Expand Up @@ -256,6 +256,14 @@ protected boolean checkApiLogic(Player ai, SpellAbility sa) {
}
}

if (sa.hasParam("SwitchPT")) {
// Some more AI would be even better, but this is a good start to prevent spamming
if (sa.isActivatedAbility() && sa.getActivationsThisTurn() > 0 && !sa.usesTargeting()) {
// Will prevent flipping back and forth
return false;
}
}

if (ComputerUtil.preventRunAwayActivations(sa)) {
return false;
}
Expand Down Expand Up @@ -364,7 +372,7 @@ protected boolean checkApiLogic(Player ai, SpellAbility sa) {
} // pumpPlayAI()

private boolean pumpTgtAI(final Player ai, final SpellAbility sa, final int defense, final int attack, final boolean mandatory,
boolean immediately) {
boolean immediately) {
final List<String> keywords = sa.hasParam("KW") ? Arrays.asList(sa.getParam("KW").split(" & "))
: Lists.newArrayList();
final Game game = ai.getGame();
Expand Down Expand Up @@ -474,6 +482,65 @@ private boolean pumpTgtAI(final Player ai, final SpellAbility sa, final int defe
}
}

if (sa.hasParam("SwitchPT")) {
// Logic to kill opponent creatures
CardCollection oppCreatures = CardLists.getTargetableCards(ai.getOpponents().getCreaturesInPlay(), sa);
if (!oppCreatures.isEmpty()) {
CardCollection oppCreaturesFiltered = CardLists.filter(oppCreatures, card -> {
// don't care about useless creatures
if (ComputerUtilCard.isUselessCreature(ai, card)
|| card.hasSVar("EndOfTurnLeavePlay")) {
return false;
}
// dies by target
if (card.getSVar("Targeting").equals("Dies")) {
return true;
}
// dies by state based action
if (card.getNetPower() <= 0) {
return true;
}
if (card.hasKeyword(Keyword.INDESTRUCTIBLE)) {
return false;
}
// check if switching PT causes it to be lethal
Card lki = CardCopyService.getLKICopy(card);
lki.addSwitchPT(-1, 0);

// check if creature could regenerate
Map<AbilityKey, Object> runParams = AbilityKey.mapFromAffected(card);
runParams.put(AbilityKey.Regeneration, true);
List<ReplacementEffect> repDestoryList = game.getReplacementHandler().getReplacementList(ReplacementType.Destroy, runParams, ReplacementLayer.Other);
// non-Regeneration one like Totem-Armor
// should do it anyway to destroy the aura?
if (Iterables.any(repDestoryList, Predicates.not(CardTraitPredicates.hasParam("Regeneration")))) {
return false;
}
// TODO make it force to use regen?
// should check phase and make it before combat damage or better before blocker?
if (Iterables.any(repDestoryList, CardTraitPredicates.hasParam("Regeneration")) && card.canBeShielded()) {
return false;
}

// maybe do it anyway to reduce its power?
if (card.getLethal() - card.getDamage() > 0) {
return false;
}
return true;
});
// the ones that die by switching PT
if (!oppCreaturesFiltered.isEmpty()) {
Card best = ComputerUtilCard.getBestCreatureAI(oppCreaturesFiltered);
if (best != null) {
sa.getTargets().add(best);
return true;
}
}
}

return false;
}

if (sa.isCurse()) {
for (final Player opp : ai.getOpponents()) {
if (sa.canTarget(opp)) {
Expand Down
1 change: 1 addition & 0 deletions forge-ai/src/main/java/forge/ai/simulation/GameCopier.java
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ private void addCard(Game newGame, ZoneType zone, Card c, Player aiPlayer) {
newCard.setPTCharacterDefiningTable(c.getSetPTCharacterDefiningTable());

newCard.setPTBoost(c.getPTBoostTable());
newCard.setSwitchPTTable(c.getSwitchPTTable());
// TODO copy by map
newCard.setDamage(c.getDamage());
newCard.setDamageReceivedThisTurn(c.getDamageReceivedThisTurn());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ private static void applyPumpAll(final SpellAbility sa,
continue;
}

boolean redrawPT = false;
boolean redrawPT = sa.hasParam("SwitchPT");

if (sa.hasParam("SwitchPT")) {
tgtC.addSwitchPT(timestamp, 0);
}

if (a != 0 || d != 0) {
if (perpetual) {
Expand Down Expand Up @@ -89,6 +93,7 @@ private static void applyPumpAll(final SpellAbility sa,

@Override
public void run() {
tgtC.removeSwitchPT(timestamp, 0);
tgtC.removePTBoost(timestamp, 0);
tgtC.removeChangedCardKeywords(timestamp, 0);
tgtC.removeHiddenExtrinsicKeywords(timestamp, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,19 @@ private static void applyPump(final SpellAbility sa, final Card applyTo,
final List<String> kws = Lists.newArrayList();
final List<String> hiddenKws = Lists.newArrayList();

boolean redrawPT = false;
boolean redrawPT = sa.hasParam("SwitchPT");
for (String kw : keywords) {
if (kw.startsWith("HIDDEN")) {
hiddenKws.add(kw.substring(7));
redrawPT |= kw.contains("CARDNAME's power and toughness are switched");
} else {
kws.add(kw);
}
}

if (sa.hasParam("SwitchPT")) {
gameCard.addSwitchPT(timestamp, 0);
}

if (a != 0 || d != 0) {
if (perpetual) {
Map <String, Object> params = new HashMap<>();
Expand Down Expand Up @@ -117,6 +120,7 @@ public void run() {
host.removeGainControlTargets(gameCard);

gameCard.removePTBoost(timestamp, 0);
gameCard.removeSwitchPT(timestamp, 0);
boolean updateText = gameCard.removeCanBlockAny(timestamp);
updateText |= gameCard.removeCanBlockAdditional(timestamp);

Expand Down
29 changes: 25 additions & 4 deletions forge-game/src/main/java/forge/game/card/Card.java
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
private Table<Long, Long, Pair<Integer,Integer>> newPTCharacterDefining = TreeBasedTable.create(); // Layer 7a
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 Table<Long, Long, Boolean> switchPT = TreeBasedTable.create(); // Layer 7d

private final Map<Card, Integer> assignedDamageMap = Maps.newTreeMap();
private Map<Integer, Integer> damage = Maps.newHashMap();
Expand Down Expand Up @@ -4513,13 +4514,13 @@ public final int getPowerBonusFromCounters() {
}

public final StatBreakdown getNetPowerBreakdown() {
if (getAmountOfKeyword("CARDNAME's power and toughness are switched") % 2 != 0) {
if (isSwitchPT()) {
return getUnswitchedToughnessBreakdown();
}
return getUnswitchedPowerBreakdown();
}
public final int getNetPower() {
if (getAmountOfKeyword("CARDNAME's power and toughness are switched") % 2 != 0) {
if (isSwitchPT()) {
return getUnswitchedToughness();
}
return getUnswitchedPower();
Expand Down Expand Up @@ -4577,7 +4578,7 @@ public final int getToughnessBonusFromCounters() {
}

public final StatBreakdown getNetToughnessBreakdown() {
if (getAmountOfKeyword("CARDNAME's power and toughness are switched") % 2 != 0) {
if (isSwitchPT()) {
return getUnswitchedPowerBreakdown();
}
return getUnswitchedToughnessBreakdown();
Expand Down Expand Up @@ -4732,10 +4733,30 @@ public Table<Long, Long, Pair<Integer, Integer>> getPTBoostTable() {
}

public void setPTBoost(Table<Long, Long, Pair<Integer, Integer>> table) {
this.boostPT.clear();
boostPT.clear();
boostPT.putAll(table);
}

public boolean isSwitchPT() {
return switchPT.values().size() % 2 != 0;
}

public void addSwitchPT(final long timestamp, final long staticId) {
switchPT.put(timestamp, staticId, Boolean.TRUE);
}

public void removeSwitchPT(final long timestamp, final long staticId) {
switchPT.remove(timestamp, staticId);
}

public Table<Long, Long, Boolean> getSwitchPTTable() {
return ImmutableTable.copyOf(switchPT);
}
public void setSwitchPTTable(Table<Long, Long, Boolean> table) {
switchPT.clear();
switchPT.putAll(table);
}

public final boolean isUntapped() {
return !tapped;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ public Card getLKICopy(Map<Integer, Card> cachedMap) {

// extra copy PT boost
newCopy.setPTBoost(copyFrom.getPTBoostTable());
newCopy.setSwitchPTTable(copyFrom.getSwitchPTTable());

newCopy.setCounters(Maps.newHashMap(copyFrom.getCounters()));

Expand Down
3 changes: 1 addition & 2 deletions forge-gui/res/cardsfolder/a/about_face.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
Name:About Face
ManaCost:R
Types:Instant
A:SP$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | KW$ HIDDEN CARDNAME's power and toughness are switched | SpellDescription$ Switch target creature's power and toughness until end of turn.
AI:RemoveDeck:All
A:SP$ Pump | ValidTgts$ Creature | SwitchPT$ True | SpellDescription$ Switch target creature's power and toughness until end of turn.
Oracle:Switch target creature's power and toughness until end of turn.
2 changes: 1 addition & 1 deletion forge-gui/res/cardsfolder/a/aeromoeba.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ ManaCost:3 U
Types:Creature Elemental Beast
PT:2/4
K:Flying
A:AB$ Pump | Cost$ Discard<1/Card> | Defined$ Self | AILogic$ SwitchPT | KW$ HIDDEN CARDNAME's power and toughness are switched | SpellDescription$ Switch CARDNAME's power and toughness until end of turn.
A:AB$ Pump | Cost$ Discard<1/Card> | Defined$ Self | SwitchPT$ True | SpellDescription$ Switch CARDNAME's power and toughness until end of turn.
Oracle:Flying\nDiscard a card: Switch Aeromoeba's power and toughness until end of turn.
3 changes: 1 addition & 2 deletions forge-gui/res/cardsfolder/a/aquamoeba.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ Name:Aquamoeba
ManaCost:1 U
Types:Creature Elemental Beast
PT:1/3
A:AB$ Pump | Cost$ Discard<1/Card> | Defined$ Self | AILogic$ SwitchPT | KW$ HIDDEN CARDNAME's power and toughness are switched | SpellDescription$ Switch CARDNAME's power and toughness until end of turn.
AI:RemoveDeck:All
A:AB$ Pump | Cost$ Discard<1/Card> | Defined$ Self | SwitchPT$ True | SpellDescription$ Switch CARDNAME's power and toughness until end of turn.
Oracle:Discard a card: Switch Aquamoeba's power and toughness until end of turn.
3 changes: 1 addition & 2 deletions forge-gui/res/cardsfolder/c/calcite_snapper.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@ Types:Creature Turtle
PT:1/4
K:Shroud
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Land.YouCtrl | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPump | TriggerDescription$ Landfall — Whenever a land you control enters, you may switch CARDNAME power and toughness until end of turn.
SVar:TrigPump:DB$ Pump | Defined$ Self | KW$ HIDDEN CARDNAME's power and toughness are switched
AI:RemoveDeck:All
SVar:TrigPump:DB$ Pump | Defined$ Self | SwitchPT$ True
Oracle:Shroud (This creature can't be the target of spells or abilities.)\nLandfall — Whenever a land you control enters, you may switch Calcite Snapper's power and toughness until end of turn.
2 changes: 1 addition & 1 deletion forge-gui/res/cardsfolder/c/crag_puca.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ Name:Crag Puca
ManaCost:UR UR UR
Types:Creature Shapeshifter
PT:2/4
A:AB$ Pump | Cost$ UR | Defined$ Self | AILogic$ SwitchPT | KW$ HIDDEN CARDNAME's power and toughness are switched | SpellDescription$ Switch CARDNAME's power and toughness until end of turn.
A:AB$ Pump | Cost$ UR | Defined$ Self | SwitchPT$ True | SpellDescription$ Switch CARDNAME's power and toughness until end of turn.
AI:RemoveDeck:All
Oracle:{U/R}: Switch Crag Puca's power and toughness until end of turn.
3 changes: 1 addition & 2 deletions forge-gui/res/cardsfolder/c/crookclaw_transmuter.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ PT:3/1
K:Flash
K:Flying
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigPump | TriggerDescription$ When CARDNAME enters, switch target creature's power and toughness until end of turn.
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | KW$ HIDDEN CARDNAME's power and toughness are switched
AI:RemoveDeck:All
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature | SwitchPT$ True
Oracle:Flash\nFlying\nWhen Crookclaw Transmuter enters, switch target creature's power and toughness until end of turn.
2 changes: 1 addition & 1 deletion forge-gui/res/cardsfolder/d/dwarven_thaumaturgist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ Name:Dwarven Thaumaturgist
ManaCost:2 R
Types:Creature Dwarf Shaman
PT:1/2
A:AB$ Pump | Cost$ T | ValidTgts$ Creature | KW$ HIDDEN CARDNAME's power and toughness are switched | TgtPrompt$ Select target creature. | SpellDescription$ Switch target creature's power and toughness until end of turn.
A:AB$ Pump | Cost$ T | ValidTgts$ Creature | SwitchPT$ True | SpellDescription$ Switch target creature's power and toughness until end of turn.
AI:RemoveDeck:All
Oracle:{T}: Switch target creature's power and toughness until end of turn.
3 changes: 1 addition & 2 deletions forge-gui/res/cardsfolder/f/fluxcharger.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ Types:Creature Weird
PT:1/5
K:Flying
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigChangePT | OptionalDecider$ You | TriggerDescription$ Whenever you cast a instant or sorcery spell, you may switch CARDNAME's power and toughness until end of turn.
SVar:TrigChangePT:DB$ Pump | KW$ HIDDEN CARDNAME's power and toughness are switched | Defined$ Self
AI:RemoveDeck:All
SVar:TrigChangePT:DB$ Pump | Defined$ Self | SwitchPT$ True
DeckHints:Type$Instant|Sorcery
Oracle:Flying\nWhenever you cast an instant or sorcery spell, you may switch Fluxcharger's power and toughness until end of turn.
3 changes: 1 addition & 2 deletions forge-gui/res/cardsfolder/i/inside_out.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
Name:Inside Out
ManaCost:1 UR
Types:Instant
A:SP$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | KW$ HIDDEN CARDNAME's power and toughness are switched | SpellDescription$ Switch target creature's power and toughness until end of turn. | SubAbility$ DBDraw
A:SP$ Pump | ValidTgts$ Creature | SwitchPT$ True | SubAbility$ DBDraw | SpellDescription$ Switch target creature's power and toughness until end of turn.
SVar:DBDraw:DB$ Draw | NumCards$ 1 | SpellDescription$ Draw a card.
AI:RemoveDeck:All
Oracle:Switch target creature's power and toughness until end of turn.\nDraw a card.
2 changes: 1 addition & 1 deletion forge-gui/res/cardsfolder/i/invert_invent.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Name:Invert
ManaCost:UR
Types:Instant
A:SP$ Pump | ValidTgts$ Creature | TargetMin$ 0 | TargetMax$ 2 | TgtPrompt$ Select target creature | KW$ HIDDEN CARDNAME's power and toughness are switched | SpellDescription$ Switch the power and toughness of each of up to two target creatures until end of turn.
A:SP$ Pump | ValidTgts$ Creature | TargetMin$ 0 | TargetMax$ 2 | SwitchPT$ True | SpellDescription$ Switch the power and toughness of each of up to two target creatures until end of turn.
AlternateMode:Split
Oracle:Switch the power and toughness of each of up to two target creatures until end of turn.

Expand Down
3 changes: 1 addition & 2 deletions forge-gui/res/cardsfolder/m/mannichi_the_fevered_dream.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ Name:Mannichi, the Fevered Dream
ManaCost:2 R
Types:Legendary Creature Spirit
PT:1/2
A:AB$ PumpAll | Cost$ 1 R | ValidCards$ Creature | KW$ HIDDEN CARDNAME's power and toughness are switched | SpellDescription$ Switch each creature's power and toughness until end of turn.
AI:RemoveDeck:All
A:AB$ PumpAll | Cost$ 1 R | ValidCards$ Creature | SwitchPT$ True | SpellDescription$ Switch each creature's power and toughness until end of turn.
Oracle:{1}{R}: Switch each creature's power and toughness until end of turn.
3 changes: 1 addition & 2 deletions forge-gui/res/cardsfolder/m/merfolk_thaumaturgist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ Name:Merfolk Thaumaturgist
ManaCost:2 U
Types:Creature Merfolk Wizard
PT:1/2
A:AB$ Pump | Cost$ T | ValidTgts$ Creature | KW$ HIDDEN CARDNAME's power and toughness are switched | TgtPrompt$ Select target creature. | SpellDescription$ Switch target creature's power and toughness until end of turn.
AI:RemoveDeck:All
A:AB$ Pump | Cost$ T | ValidTgts$ Creature | SwitchPT$ True | SpellDescription$ Switch target creature's power and toughness until end of turn.
Oracle:{T}: Switch target creature's power and toughness until end of turn.
2 changes: 1 addition & 1 deletion forge-gui/res/cardsfolder/m/myr_quadropod.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ Name:Myr Quadropod
ManaCost:4
Types:Artifact Creature Myr
PT:1/4
A:AB$ Pump | Cost$ 3 | Defined$ Self | AILogic$ SwitchPT | KW$ HIDDEN CARDNAME's power and toughness are switched | SpellDescription$ Switch CARDNAME's power and toughness until end of turn.
A:AB$ Pump | Cost$ 3 | Defined$ Self | SwitchPT$ True | SpellDescription$ Switch CARDNAME's power and toughness until end of turn.
AI:RemoveDeck:All
Oracle:{3}: Switch Myr Quadropod's power and toughness until end of turn.
Loading
Loading