mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 02:38:02 +00:00
C21 Veyran & Panharmonicon rework
This commit is contained in:
@@ -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")) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user