mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 10:18:01 +00:00
Hidden and Double Agenda better as Keyword (#7093)
* Hidden and Double Agenda better as Keyword
This commit is contained in:
@@ -1389,11 +1389,11 @@ public class PlayerControllerAi extends PlayerController {
|
||||
oppLibrary = CardLists.getValidCards(oppLibrary, valid, source.getController(), source, sa);
|
||||
}
|
||||
|
||||
if (source != null && source.getState(CardStateName.Original).hasIntrinsicKeyword("Hidden agenda")) {
|
||||
if (source != null && source.getState(CardStateName.Original).hasKeyword(Keyword.HIDDEN_AGENDA)) {
|
||||
// If any Conspiracies are present, try not to choose the same name twice
|
||||
// (otherwise the AI will spam the same name)
|
||||
for (Card consp : player.getCardsIn(ZoneType.Command)) {
|
||||
if (consp.getState(CardStateName.Original).hasIntrinsicKeyword("Hidden agenda")) {
|
||||
if (consp.getState(CardStateName.Original).hasKeyword(Keyword.HIDDEN_AGENDA)) {
|
||||
String chosenName = consp.getNamedCard();
|
||||
if (!chosenName.isEmpty()) {
|
||||
aiLibrary = CardLists.filter(aiLibrary, CardPredicates.nameNotEquals(chosenName));
|
||||
|
||||
@@ -6,6 +6,7 @@ import forge.ai.SpellAbilityAi;
|
||||
import forge.card.CardStateName;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.*;
|
||||
import forge.game.keyword.Keyword;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
@@ -142,7 +143,7 @@ public class SetStateAi extends SpellAbilityAi {
|
||||
return false;
|
||||
}
|
||||
// hidden agenda
|
||||
if (card.getState(CardStateName.Original).hasIntrinsicKeyword("Hidden agenda")
|
||||
if (card.getState(CardStateName.Original).hasKeyword(Keyword.HIDDEN_AGENDA)
|
||||
&& card.isInZone(ZoneType.Command)) {
|
||||
String chosenName = card.getNamedCard();
|
||||
for (Card cast : ai.getGame().getStack().getSpellsCastThisTurn()) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.*;
|
||||
import forge.game.event.GameEventCardStatsChanged;
|
||||
import forge.game.keyword.Keyword;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerActionConfirmMode;
|
||||
import forge.game.trigger.TriggerHandler;
|
||||
@@ -53,7 +54,6 @@ public class SetStateEffect extends SpellAbilityEffect {
|
||||
final Game game = host.getGame();
|
||||
|
||||
final boolean remChanged = sa.hasParam("RememberChanged");
|
||||
final boolean hiddenAgenda = sa.hasParam("HiddenAgenda");
|
||||
final boolean optional = sa.hasParam("Optional");
|
||||
final CardCollection transformedCards = new CardCollection();
|
||||
|
||||
@@ -194,8 +194,8 @@ public class SetStateEffect extends SpellAbilityEffect {
|
||||
} else if (sa.isCloakUp()) {
|
||||
String sb = p + " has uncloaked " + gameCard.getName();
|
||||
game.getGameLog().add(GameLogEntryType.STACK_RESOLVE, sb);
|
||||
} else if (hiddenAgenda) {
|
||||
if (gameCard.hasKeyword("Double agenda")) {
|
||||
} else if (sa.isKeyword(Keyword.HIDDEN_AGENDA) || sa.isKeyword(Keyword.DOUBLE_AGENDA)) {
|
||||
if (sa.isKeyword(Keyword.DOUBLE_AGENDA)) {
|
||||
String sb = p + " has revealed " + gameCard.getName() + " with the chosen names: " + gameCard.getNamedCards();
|
||||
game.getGameLog().add(GameLogEntryType.STACK_RESOLVE, sb);
|
||||
} else {
|
||||
|
||||
@@ -7591,6 +7591,14 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
abilities.addAll(GameActionUtil.getAlternativeCosts(sa, player, false));
|
||||
}
|
||||
}
|
||||
if (isFaceDown() && isInZone(ZoneType.Command)) {
|
||||
for (KeywordInterface k : oState.getCachedKeyword(Keyword.HIDDEN_AGENDA)) {
|
||||
abilities.addAll(k.getAbilities());
|
||||
}
|
||||
for (KeywordInterface k : oState.getCachedKeyword(Keyword.DOUBLE_AGENDA)) {
|
||||
abilities.addAll(k.getAbilities());
|
||||
}
|
||||
}
|
||||
// Add Modal Spells
|
||||
if (isModal() && hasState(CardStateName.Modal)) {
|
||||
for (SpellAbility sa : getState(CardStateName.Modal).getSpellAbilities()) {
|
||||
|
||||
@@ -215,7 +215,7 @@ public class CardFactoryUtil {
|
||||
return manifestUp;
|
||||
}
|
||||
|
||||
public static boolean handleHiddenAgenda(Player player, Card card) {
|
||||
public static boolean handleHiddenAgenda(Player player, Card card, KeywordInterface ki) {
|
||||
SpellAbility sa = new SpellAbility.EmptySa(card);
|
||||
sa.putParam("AILogic", card.getSVar("AgendaLogic"));
|
||||
Predicate<ICardFace> cpp = x -> true;
|
||||
@@ -228,7 +228,7 @@ public class CardFactoryUtil {
|
||||
}
|
||||
card.addNamedCard(name);
|
||||
|
||||
if (card.hasKeyword("Double agenda")) {
|
||||
if (ki.getKeyword().equals(Keyword.DOUBLE_AGENDA)) {
|
||||
String name2 = player.getController().chooseCardName(sa, cpp, "Card.!NamedCard",
|
||||
"Name a second card for " + card.getName());
|
||||
if (name2 == null || name2.isEmpty()) {
|
||||
@@ -239,14 +239,14 @@ public class CardFactoryUtil {
|
||||
|
||||
card.turnFaceDown();
|
||||
card.addMayLookAt(player.getGame().getNextTimestamp(), ImmutableList.of(player));
|
||||
card.addSpellAbility(abilityRevealHiddenAgenda(card));
|
||||
ki.addSpellAbility(abilityRevealHiddenAgenda(card));
|
||||
return true;
|
||||
}
|
||||
|
||||
private static SpellAbility abilityRevealHiddenAgenda(final Card sourceCard) {
|
||||
String ab = "ST$ SetState | Cost$ 0"
|
||||
+ " | ConditionDefined$ Self | ConditionPresent$ Card.faceDown+inZoneCommand"
|
||||
+ " | HiddenAgenda$ True"
|
||||
+ " | PresentDefined$ Self | IsPresent$ Card.faceDown+inZoneCommand"
|
||||
+ " | ActivationZone$ Command | Secondary$ True"
|
||||
+ " | Mode$ TurnFaceUp | SpellDescription$ Reveal this Hidden Agenda at any time.";
|
||||
return AbilityFactory.getAbility(ab, sourceCard);
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ public enum Keyword {
|
||||
DISGUISE("Disguise", KeywordWithCost.class, false, "You may cast this card face down for {3} as a 2/2 creature with ward {2}. Turn it face up any time for its disguise cost."),
|
||||
DISTURB("Disturb", KeywordWithCost.class, false, "You may cast this card from your graveyard transformed for its disturb cost."),
|
||||
DOCTORS_COMPANION("Doctor's companion", Partner.class, true, "You can have two commanders if the other is the Doctor."),
|
||||
DOUBLE_AGENDA("Double agenda", SimpleKeyword.class, false, "Start the game with this conspiracy face down in the command zone and secretly choose two different card names. You may turn this conspiracy face up any time and reveal those names."),
|
||||
DOUBLE_STRIKE("Double Strike", SimpleKeyword.class, true, "This creature deals both first-strike and regular combat damage."),
|
||||
DOUBLE_TEAM("Double team", SimpleKeyword.class, true, "When this creature attacks, if it's not a token, conjure a duplicate of it into your hand. Then both cards perpetually lose double team."),
|
||||
DREDGE("Dredge", KeywordWithAmount.class, false, "If you would draw a card, instead you may put exactly {%d:card} from the top of your library into your graveyard. If you do, return this card from your graveyard to your hand. Otherwise, draw a card."),
|
||||
@@ -99,6 +100,7 @@ public enum Keyword {
|
||||
HAUNT("Haunt", SimpleKeyword.class, false, "When this is put into a graveyard, exile it haunting target creature."),
|
||||
HEXPROOF("Hexproof", Hexproof.class, true, "This can't be the target of %s spells or abilities your opponents control."),
|
||||
HIDEAWAY("Hideaway", KeywordWithAmount.class, false, "When this permanent enters, look at the top {%d:card} of your library, exile one face down, then put the rest on the bottom of your library."),
|
||||
HIDDEN_AGENDA("Hidden agenda", SimpleKeyword.class, false, "Start the game with this conspiracy face down in the command zone and secretly choose a card name. You may turn this conspiracy face up any time and reveal that name."),
|
||||
HORSEMANSHIP("Horsemanship", SimpleKeyword.class, true, "This creature can't be blocked except by creatures with horsemanship."),
|
||||
IMPENDING("Impending", KeywordWithCostAndAmount.class, false, "If you cast this spell for its impending cost, it enters with {%2$d:time counter} and isn't a creature until the last is removed. At the beginning of your end step, remove a time counter from it."),
|
||||
IMPROVISE("Improvise", SimpleKeyword.class, true, "Your artifacts can help cast this spell. Each artifact you tap after you're done activating mana abilities pays for {1}."),
|
||||
|
||||
@@ -3079,9 +3079,15 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
// Conspiracies
|
||||
for (IPaperCard cp : registeredPlayer.getConspiracies()) {
|
||||
Card conspire = Card.fromPaperCard(cp, this);
|
||||
if (conspire.hasKeyword("Hidden agenda") || conspire.hasKeyword("Double agenda")) {
|
||||
if (!CardFactoryUtil.handleHiddenAgenda(this, conspire)) {
|
||||
continue;
|
||||
boolean addToCommand = true;
|
||||
for (KeywordInterface ki : conspire.getKeywords(Keyword.HIDDEN_AGENDA)) {
|
||||
if (!CardFactoryUtil.handleHiddenAgenda(this, conspire, ki)) {
|
||||
addToCommand = false;
|
||||
}
|
||||
}
|
||||
for (KeywordInterface ki : conspire.getKeywords(Keyword.DOUBLE_AGENDA)) {
|
||||
if (!CardFactoryUtil.handleHiddenAgenda(this, conspire, ki)) {
|
||||
addToCommand = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3093,7 +3099,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
this.extraZones.add(hand);
|
||||
}
|
||||
|
||||
com.add(conspire);
|
||||
if (addToCommand) {
|
||||
com.add(conspire);
|
||||
}
|
||||
}
|
||||
|
||||
// Attractions
|
||||
|
||||
@@ -229,11 +229,6 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
|
||||
|
||||
if (cardZone == null || this.getZone() == null || !cardZone.is(this.getZone())) {
|
||||
// If Card is not in the default activating zone, do some additional checks
|
||||
|
||||
// A conspiracy with hidden agenda: reveal at any time
|
||||
if (cardZone != null && cardZone.is(ZoneType.Command) && sa.hasParam("HiddenAgenda")) {
|
||||
return true;
|
||||
}
|
||||
if (sa.hasParam("AdditionalActivationZone")) {
|
||||
if (cardZone != null && cardZone.is(ZoneType.valueOf(sa.getParam("AdditionalActivationZone")))) {
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user