C21 Veyran & Panharmonicon rework

This commit is contained in:
Hythonia
2021-04-09 15:15:29 +00:00
committed by Hans Mackowiak
parent c93c582ed5
commit cc8e8b2dd1
13 changed files with 169 additions and 138 deletions

View File

@@ -1898,8 +1898,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
}
}
}
if (keyword.startsWith("CantBeCounteredBy") || keyword.startsWith("Panharmonicon")
|| keyword.startsWith("Dieharmonicon") || keyword.startsWith("Shrineharmonicon")) {
if (keyword.startsWith("CantBeCounteredBy")) {
final String[] p = keyword.split(":");
sbLong.append(p[2]).append("\r\n");
} else if (keyword.startsWith("etbCounter")) {

View File

@@ -34,6 +34,7 @@ import forge.game.GameEntity;
import forge.game.GameStage;
import forge.game.IIdentifiable;
import forge.game.ability.AbilityUtils;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
@@ -45,6 +46,7 @@ import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.trigger.Trigger;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.util.CardTranslation;
@@ -458,6 +460,19 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
return false;
}
public final boolean applyAbility(final String mode, final Trigger trigger, final Map<AbilityKey, Object> runParams) {
// don't apply the ability if it hasn't got the right mode
if (!getParam("Mode").equals(mode)) {
return false;
}
if (mode.equals("Panharmonicon")) {
return StaticAbilityPanharmonicon.applyPanharmoniconAbility(this, trigger, runParams);
}
return false;
}
public final Cost getAttackCost(final Card attacker, final GameEntity target) {
if (this.isSuppressed() || !getParam("Mode").equals("CantAttackUnless") || !this.checkConditions()) {
return null;

View File

@@ -0,0 +1,98 @@
package forge.game.staticability;
import com.google.common.collect.ImmutableList;
import forge.game.Game;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.card.CardZoneTable;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class StaticAbilityPanharmonicon {
public static boolean applyPanharmoniconAbility(final StaticAbility stAb, final Trigger trigger, final Map<AbilityKey, Object> runParams) {
final Card card = stAb.getHostCard();
final Game game = card.getGame();
final Card trigHost = trigger.getHostCard();
final TriggerType trigMode = trigger.getMode();
// What card is the source of the trigger?
if (!stAb.matchesValidParam("ValidCard", trigHost)) {
return false;
}
// Is our trigger's mode among the other modes?
if (stAb.hasParam("ValidMode")) {
List<String> modes = new ArrayList<>(Arrays.asList(stAb.getParam("ValidMode").split(",")));
if (!modes.contains(trigMode.toString())) {
return false;
}
}
if (trigMode.equals(TriggerType.ChangesZone)) {
// Cause of the trigger the card changing zones
final Card trigCause = (Card) runParams.get(AbilityKey.Card);
if (stAb.hasParam("ValidCause")) {
if (!trigCause.isValid(stAb.getParam("ValidCause").split(","),
game.getPhaseHandler().getPlayerTurn(), trigHost, null)) {
return false;
}
}
if (stAb.hasParam("Origin")) {
final String origin = (String) runParams.get(AbilityKey.Origin);
if (!origin.equals(stAb.getParam("Origin"))) {
return false;
}
}
if (stAb.hasParam("Destination")) {
final String destination = (String) runParams.get(AbilityKey.Destination);
if (!destination.equals(stAb.getParam("Destination"))) {
return false;
}
}
} else if (trigMode.equals(TriggerType.ChangesZoneAll)) {
// Check if the cards have a trigger at all
final String origin = stAb.hasParam("Origin") ? stAb.getParam("Origin") : null;
final String destination = stAb.hasParam("Destination") ? stAb.getParam("Destination") : null;
final CardZoneTable table = (CardZoneTable) runParams.get(AbilityKey.Cards);
// If the origin isn't specified, it's null not making a list out of that.
if (origin == null) {
if (table.filterCards(null, ZoneType.smartValueOf(destination), stAb.getParam("ValidCause"), trigHost, null).isEmpty()) {
return false;
}
} else {
if (table.filterCards(ImmutableList.of(ZoneType.smartValueOf(origin)), ZoneType.smartValueOf(destination), stAb.getParam("ValidCause"), trigHost, null).isEmpty()) {
return false;
}
}
} else if (trigMode.equals(TriggerType.SpellCastOrCopy)
|| trigMode.equals(TriggerType.SpellCast) || trigMode.equals(TriggerType.SpellCopy)) {
// Check if the spell cast and the caster match
final SpellAbility sa = (SpellAbility) runParams.get(AbilityKey.CastSA);
if (stAb.hasParam("ValidCause")) {
if (!sa.getHostCard().isValid(stAb.getParam("ValidCause").split(","),
game.getPhaseHandler().getPlayerTurn(), trigHost, null)) {
return false;
}
}
if (stAb.hasParam("ValidActivator")) {
if (!sa.getActivatingPlayer().isValid(stAb.getParam("ValidActivator").split(","),
game.getPhaseHandler().getPlayerTurn(), trigHost, null)) {
return false;
}
}
}
return true;
}
}

View File

@@ -34,16 +34,12 @@ import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.effects.CharmEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardState;
import forge.game.card.CardZoneTable;
import forge.game.card.*;
import forge.game.keyword.KeywordInterface;
import forge.game.player.Player;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbility;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.util.FileSection;
@@ -362,7 +358,7 @@ public class TriggerHandler {
for (final Trigger t : triggers) {
if (!t.isStatic() && t.getHostCard().getController().equals(player) && canRunTrigger(t, mode, runParams)) {
int x = 1 + handlePanharmonicon(t, runParams, player);
int x = 1 + handlePanharmonicon(t, runParams);
for (int i = 0; i < x; ++i) {
runSingleTrigger(t, runParams);
@@ -626,100 +622,14 @@ public class TriggerHandler {
}
}
private int handlePanharmonicon(final Trigger t, final Map<AbilityKey, Object> runParams, final Player p) {
Card host = t.getHostCard();
private int handlePanharmonicon(final Trigger t, final Map<AbilityKey, Object> runParams) {
int n = 0;
// Sanctum of All
if (host.isShrine() && host.isInZone(ZoneType.Battlefield) && p.equals(host.getController())) {
int shrineCount = CardLists.count(p.getCardsIn(ZoneType.Battlefield), CardPredicates.isType("Shrine"));
if (shrineCount >= 6) {
for (final Card ck : p.getCardsIn(ZoneType.Battlefield)) {
for (final KeywordInterface ki : ck.getKeywords()) {
final String kw = ki.getOriginal();
if (kw.startsWith("Shrineharmonicon")) {
final String valid = kw.split(":")[1];
if (host.isValid(valid.split(","), p, ck, null)) {
n++;
}
}
}
}
}
}
// not a changesZone trigger or changesZoneAll
if (t.getMode() != TriggerType.ChangesZone && t.getMode() != TriggerType.ChangesZoneAll) {
return n;
}
// leave battlefield trigger, might be dying
// only real changeszone look back for this
if (t.getMode() == TriggerType.ChangesZone && "Battlefield".equals(t.getParam("Origin"))) {
// Need to get the last info from the trigger host
host = game.getChangeZoneLKIInfo(host);
}
// not a Permanent you control
if (!host.isPermanent() || !host.isInZone(ZoneType.Battlefield)) {
return 0;
}
if (t.getMode() == TriggerType.ChangesZone) {
// iterate over all cards
for (final Card ck : CardLists.filterControlledBy(p.getGame().getLastStateBattlefield(), p)) {
for (final KeywordInterface ki : ck.getKeywords()) {
final String kw = ki.getOriginal();
if (kw.startsWith("Panharmonicon")) {
// Enter the Battlefield Trigger
if (runParams.get(AbilityKey.Destination) instanceof String) {
final String dest = (String) runParams.get(AbilityKey.Destination);
if ("Battlefield".equals(dest) && runParams.get(AbilityKey.Card) instanceof Card) {
final Card card = (Card) runParams.get(AbilityKey.Card);
final String valid = kw.split(":")[1];
if (card.isValid(valid.split(","), p, ck, null)) {
n++;
}
}
}
} else if (kw.startsWith("Dieharmonicon")) {
// 700.4. The term dies means "is put into a graveyard from the battlefield."
if (runParams.get(AbilityKey.Origin) instanceof String) {
final String origin = (String) runParams.get(AbilityKey.Origin);
if ("Battlefield".equals(origin) && runParams.get(AbilityKey.Destination) instanceof String) {
final String dest = (String) runParams.get(AbilityKey.Destination);
if ("Graveyard".equals(dest) && runParams.get(AbilityKey.Card) instanceof Card) {
final Card card = (Card) runParams.get(AbilityKey.Card);
final String valid = kw.split(":")[1];
if (card.isValid(valid.split(","), p, ck, null)) {
n++;
}
}
}
}
}
}
}
} else if (t.getMode() == TriggerType.ChangesZoneAll) {
final CardZoneTable table = (CardZoneTable) runParams.get(AbilityKey.Cards);
// iterate over all cards that are on the battlefield right now, don't use last state
for (final Card ck : p.getCardsIn(ZoneType.Battlefield)) {
for (final KeywordInterface ki : ck.getKeywords()) {
final String kw = ki.getOriginal();
if (kw.startsWith("Panharmonicon")) {
// currently there is no ChangesZoneAll that would trigger on etb
final String valid = kw.split(":")[1];
if (!table.filterCards(null, ZoneType.Battlefield, valid, ck, null).isEmpty()) {
n++;
}
} else if (kw.startsWith("Dieharmonicon")) {
// 700.4. The term dies means "is put into a graveyard from the battlefield."
final String valid = kw.split(":")[1];
if (!table.filterCards(ImmutableList.of(ZoneType.Battlefield), ZoneType.Graveyard,
valid, ck, null).isEmpty()) {
n++;
}
}
// Checks only the battlefield, as those effects only work from there
for (final Card ca : game.getLastStateBattlefield()) {
for (final StaticAbility stAb : ca.getStaticAbilities()) {
if (stAb.applyAbility("Panharmonicon", t, runParams) && stAb.checkConditions()) {
n++;
}
}
}