Secret Council mechanic and cards (#3542)

This commit is contained in:
Northmoc
2023-07-28 13:30:13 -04:00
committed by GitHub
parent f6537fdb1a
commit d0777fce21
17 changed files with 100 additions and 9 deletions

View File

@@ -13,12 +13,14 @@ import forge.game.GameEntityCounterTable;
import forge.game.GameObject;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.*;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.trigger.TriggerType;
import forge.game.trigger.WrappedAbility;
import forge.game.zone.ZoneType;
import forge.util.collect.FCollection;
@@ -101,6 +103,9 @@ public class RepeatEachEffect extends SpellAbilityEffect {
} else {
source.addRemembered(card);
}
if (sa.hasParam("AmountFromVotes")) {
setVoteAmount(card, sa);
}
AbilityUtils.resolve(repeat);
if (useImprinted) {
source.removeImprintedCard(card);
@@ -199,6 +204,9 @@ public class RepeatEachEffect extends SpellAbilityEffect {
List<Object> tempRemembered = Lists.newArrayList(Iterables.filter(source.getRemembered(), Player.class));
source.removeRemembered(tempRemembered);
source.addRemembered(p);
if (sa.hasParam("AmountFromVotes")) {
setVoteAmount(p, sa);
}
AbilityUtils.resolve(repeat);
source.removeRemembered(p);
source.addRemembered(tempRemembered);
@@ -222,4 +230,19 @@ public class RepeatEachEffect extends SpellAbilityEffect {
sa.setLoseLifeMap(null);
}
}
private void setVoteAmount (Object o, SpellAbility sa) {
SpellAbility rootAbility = sa.getRootAbility();
if (rootAbility.isWrapper()) {
rootAbility = ((WrappedAbility) rootAbility).getWrappedAbility();
}
final SpellAbility saVote = rootAbility.getApi().equals(ApiType.Vote) ? rootAbility
: rootAbility.findSubAbilityByType(ApiType.Vote);
if (saVote == null) {
System.err.println(sa.getHostCard() + ": Bad vote amount for " + o + ", default to 0");
sa.setSVar("Votes", "Number$0");
} else {
sa.setSVar("Votes", saVote.getSVar("VoteNum" + o.toString()));
}
}
}

View File

@@ -56,18 +56,21 @@ public class VoteEffect extends SpellAbilityEffect {
final Card host = sa.getHostCard();
final Game game = host.getGame();
final Player activator = sa.getActivatingPlayer();
final boolean secret = sa.hasParam("Secret");
final StringBuilder secretSB = new StringBuilder();
if (sa.hasParam("VoteType")) {
voteType.addAll(Arrays.asList(sa.getParam("VoteType").split(",")));
} else if (sa.hasParam("VoteCard")) {
ZoneType zone = sa.hasParam("Zone") ? ZoneType.smartValueOf(sa.getParam("Zone")) : ZoneType.Battlefield;
voteType.addAll(CardLists.getValidCards(game.getCardsIn(zone), sa.getParam("VoteCard"), activator, host, sa));
} else if (sa.hasParam("VotePlayer")) {
voteType.addAll(AbilityUtils.getDefinedPlayers(host, sa.getParam("VotePlayer"), sa));
}
if (voteType.isEmpty()) {
return;
}
// starting with the activator
int aidx = tgtPlayers.indexOf(activator);
if (aidx != -1) {
@@ -88,13 +91,25 @@ public class VoteEffect extends SpellAbilityEffect {
voteAmount += p.getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblHowManyAdditionalVotesDoYouWant"), 0, optionalVotes, params);
for (int i = 0; i < voteAmount; i++) {
Object result = realVoter.getController().vote(sa, host + Localizer.getInstance().getMessage("lblVote") + ":", voteType, votes, p);
Object result = realVoter.getController().vote(sa, host + " " + Localizer.getInstance().getMessage("lblVote") + ":", voteType, votes, p);
votes.put(result, p);
host.getGame().getAction().notifyOfValue(sa, p, result + "\r\n" + Localizer.getInstance().getMessage("lblCurrentVote") + ":" + votes, p);
if (!secret) {
game.getAction().notifyOfValue(sa, p, result + "\r\n" +
Localizer.getInstance().getMessage("lblCurrentVote") + ":" + votes, p);
} else {
if (secretSB.length() > 0) {
secretSB.append("\r\n");
}
secretSB.append(p).append(" ").append(Localizer.getInstance().getMessage("lblVotedFor", result));
}
}
}
if (secret) {
game.getAction().notifyOfValue(sa, host, secretSB.toString(), null);
}
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put(AbilityKey.AllVotes, votes);
game.getTriggerHandler().runTrigger(TriggerType.Vote, runParams, false);
@@ -140,6 +155,9 @@ public class VoteEffect extends SpellAbilityEffect {
if (sa.hasParam("VoteSubAbility")) {
host.clearRemembered();
}
if (sa.hasParam("RememberVotedObjects")) {
host.addRemembered(votes.keySet());
}
}
}
@@ -158,5 +176,4 @@ public class VoteEffect extends SpellAbilityEffect {
}
return most;
}
}

View File

@@ -72,8 +72,12 @@ public class MessageUtil {
case PutCounter:// For Clay Golem cost text
return value;
case Vote:
String chooser = StringUtils.capitalize(mayBeYou(player, target));
return Localizer.getInstance().getMessage("lblPlayerVoteValue", chooser, value);
if (sa.hasParam("Secret")) {
return value;
} else {
String chooser = StringUtils.capitalize(mayBeYou(player, target));
return Localizer.getInstance().getMessage("lblPlayerVoteValue", chooser, value);
}
default:
String tgt = mayBeYou(player, target);
if (tgt.equals("(null)")) {

View File

@@ -2,7 +2,7 @@ Name:Buzzing Whack-a-Doodle
ManaCost:4
Types:Artifact
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ ChooseOpp | Static$ True | TriggerDescription$ As Buzzing Whack-a-Doodle enters the battlefield, you and an opponent each secretly choose Whack or Doodle. Then those choices are revealed. If the choices match, Buzzing Whack-a-Doodle has that ability. Otherwise, it has Buzz. • Whack — {T}: Target player loses 2 life. • Doodle — {T}: You gain 3 life. • Buzz — {2}, {T}: Draw a card.
SVar:ChooseOpp:DB$ ChoosePlayer | Defined$ You | Choices$ Player.Opponent | ChoiceTitle$ Choose an opponent | SubAbility$ YouChoice
SVar:ChooseOpp:DB$ ChoosePlayer | Defined$ You | Choices$ Opponent | ChoiceTitle$ Choose an opponent | SubAbility$ YouChoice
SVar:YouChoice:DB$ GenericChoice | Choices$ YouWhack,YouDoodle | Defined$ You | AILogic$ Random | SubAbility$ StoreYou
SVar:YouWhack:DB$ StoreSVar | SVar$ Doodles | Type$ Number | Expression$ 0 | SpellDescription$ Whack
SVar:YouDoodle:DB$ StoreSVar | SVar$ Doodles | Type$ Number | Expression$ 1 | SpellDescription$ Doodle

View File

@@ -4,7 +4,7 @@ Types:Legendary Creature Sphinx Rogue
PT:6/6
K:Flying
K:Ward:3
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigVote | TriggerDescription$ Council's dilemma — Whenever Tivit enters the battlefield or deals combat damage to a player, starting with you, each player votes for evidence or bribery. For each evidence vote, investigate. For each bribery vote, create a Treasure token.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigVote | TriggerDescription$ Council's dilemma — Whenever NICKNAME enters the battlefield or deals combat damage to a player, starting with you, each player votes for evidence or bribery. For each evidence vote, investigate. For each bribery vote, create a Treasure token.
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigVote | TriggerZones$ Battlefield | Secondary$ True | TriggerDescription$ Council's dilemma — Whenever Tivit enters the battlefield or deals combat damage to a player, starting with you, each player votes for evidence or bribery. For each evidence vote, investigate. For each bribery vote, create a Treasure token.
SVar:TrigVote:DB$ Vote | Defined$ Player | StoreVoteNum$ True | VoteType$ Evidence,Bribery | SubAbility$ DBEvidence
SVar:DBEvidence:DB$ Investigate | Defined$ You | Num$ VoteNumEvidence | SubAbility$ DBBribery

View File

@@ -0,0 +1,13 @@
Name:Cirdan the Shipwright
ManaCost:3 G U
Types:Legendary Creature Elf Noble
PT:3/4
K:Vigilance
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigVote | TriggerDescription$ Secret council — Whenever CARDNAME enters the battlefield or attacks, each player secretly votes for a player, then those votes are revealed. Each player draws a card for each vote they received. Each player who received no votes may put a permanent card from their hand onto the battlefield.
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigVote | Secondary$ True | TriggerZones$ Battlefield | TriggerDescription$ Secret council — Whenever CARDNAME enters the battlefield or attacks, each player secretly votes for a player, then those votes are revealed. Each player draws a card for each vote they received. Each player who received no votes may put a permanent card from their hand onto the battlefield.
SVar:TrigVote:DB$ Vote | Defined$ Player | Secret$ True | VotePlayer$ Player | StoreVoteNum$ True | SubAbility$ DBRepeatDraw
SVar:DBRepeatDraw:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBDraw | AmountFromVotes$ True | SubAbility$ DBRepeatPut
SVar:DBDraw:DB$ Draw | Defined$ Remembered | NumCards$ Votes
SVar:DBRepeatPut:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBChangeZone | AmountFromVotes$ True | SubAbility$ DBChangeZone
SVar:DBChangeZone:DB$ ChangeZone | DefinedPlayer$ Remembered | ConditionCheckSVar$ Votes | ConditionSVarCompare$ EQ0 | ChangeType$ Permanent | Origin$ Hand | Destination$ Battlefield
Oracle:Vigilance\nSecret council — Whenever Cirdan the Shipwright enters the battlefield or attacks, each player secretly votes for a player, then those votes are revealed. Each player draws a card for each vote they received. Each player who received no votes may put a permanent card from their hand onto the battlefield.

View File

@@ -0,0 +1,17 @@
Name:Elrond of the White Council
ManaCost:3 G U
Types:Legendary Creature Elf Noble
PT:3/3
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigVote | TriggerDescription$ Secret council — When CARDNAME enters the battlefield, each player secretly votes for fellowship or aid, then those votes are revealed. For each fellowship vote, the voter chooses a creature they control. You gain control of each creature chosen this way, and they gain "This creature can't attack its owner." Then for each aid vote, put a +1/+1 counter on each creature you control.
SVar:TrigVote:DB$ Vote | Defined$ Player | Secret$ True | VoteType$ Fellowship,Aid | VoteFellowship$ Fellowship | VoteAid$ AidPlus | EachVote$ True | SubAbility$ DBGainControl
SVar:Fellowship:DB$ ChooseCard | Defined$ Remembered | Amount$ 1 | Choices$ Creature.RememberedPlayerCtrl | ChoiceTitle$ Choose a creature you control | ImprintChosen$ True | Mandatory$ True
SVar:AidPlus:DB$ StoreSVar | SVar$ Aid | Type$ CountSVar | Expression$ Aid/Plus.1
SVar:DBGainControl:DB$ GainControl | Defined$ Imprinted | NewController$ You | SubAbility$ DBAnimate
SVar:DBAnimate:DB$ Animate | Defined$ Imprinted | staticAbilities$ CantAttackOwner | SubAbility$ DBPutCounter
SVar:CantAttackOwner:Mode$ CantAttack | ValidCard$ Card.Self | Target$ Player.CardOwner | Description$ This creature can't attack its owner.
SVar:DBPutCounter:DB$ PutCounterAll | ValidCards$ Creature.YouCtrl | CounterType$ P1P1 | CounterNum$ Aid | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearImprinted$ True | ClearChosenCard$ True | SubAbility$ DBClearSVar
SVar:DBClearSVar:DB$ StoreSVar | SVar$ Aid | Type$ Number | Expression$ 0
SVar:Aid:Number$0
DeckHas:Ability$Counters
Oracle:Secret council — When Elrond of the White Council enters the battlefield, each player secretly votes for fellowship or aid, then those votes are revealed. For each fellowship vote, the voter chooses a creature they control. You gain control of each creature chosen this way, and they gain "This creature can't attack its owner." Then for each aid vote, put a +1/+1 counter on each creature you control.

View File

@@ -0,0 +1,9 @@
Name:Trap the Trespassers
ManaCost:2 U
Types:Instant
A:SP$ Vote | Defined$ Player | Secret$ True | StoreVoteNum$ True | VoteCard$ Creature.YouDontCtrl | RememberVotedObjects$ True | AILogic$ Judgment | SubAbility$ DBRepeatStun | StackDescription$ SpellDescription | SpellDescription$ Secret council — Each player secretly votes for a creature you don't control, then those votes are revealed.
SVar:DBRepeatStun:DB$ RepeatEach | UseImprinted$ True | DefinedCards$ Remembered | RepeatSubAbility$ DBPutCounter | AmountFromVotes$ True | SubAbility$ DBCleanup | SpellDescription$ For each creature with one or more votes, put that many stun counters on it, then tap it. (If a permanent with a stun counter would become untapped, remove one from it instead.)
SVar:DBPutCounter:DB$ PutCounter | Defined$ Imprinted | CounterType$ STUN | CounterNum$ Votes | SubAbility$ DBTap
SVar:DBTap:DB$ Tap | Defined$ Imprinted
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
Oracle:Secret council — Each player secretly votes for a creature you don't control, then those votes are revealed. For each creature with one or more votes, put that many stun counters on it, then tap it. (If a permanent with a stun counter would become untapped, remove one from it instead.)

View File

@@ -3,7 +3,7 @@ ManaCost:2 B
Types:Instant
K:Ascend
A:SP$ Sacrifice | Cost$ 2 B | SacValid$ Creature | Defined$ Player.Opponent | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ0 | SubAbility$ DBRepeatEach | SpellDescription$ Each opponent sacrifices a creature. If you have the city's blessing, instead each opponent sacrifices half the creatures they control, rounded up.
SVar:DBRepeatEach:DB$ RepeatEach | RepeatPlayers$ Player.Opponent | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ1 | RepeatSubAbility$ DBSacrifice
SVar:DBRepeatEach:DB$ RepeatEach | RepeatPlayers$ Opponent | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ1 | RepeatSubAbility$ DBSacrifice
SVar:DBSacrifice:DB$ Sacrifice | Amount$ Y | SacValid$ Creature | Defined$ Remembered
SVar:X:Count$Blessing.1.0
SVar:Y:Count$Valid Creature.RememberedPlayerCtrl/HalfUp

View File

@@ -2086,6 +2086,7 @@ lblChooseRoom=Welchen Raum möchtest du betreten?
#VoteEffect.java
lblVote=Abstimmung
lblCurrentVote=Aktuelle Stimmen
lblVotedFor=hat für {0} gestimmt
lblHowManyAdditionalVotesDoYouWant=Wie viele zusätzliche Stimmen möchtest du?
#VDevMenu.java
lblUnlimitedLands=Spiele beliebige Länder

View File

@@ -2091,6 +2091,7 @@ lblChooseRoom=Which room do you want to venture into?
#VoteEffect.java
lblVote=Vote
lblCurrentVote=Current Votes
lblVotedFor=voted for {0}
lblHowManyAdditionalVotesDoYouWant=How many additional votes do you want?
#VDevMenu.java
lblUnlimitedLands=Play Unlimited Lands

View File

@@ -2087,6 +2087,7 @@ lblChooseRoom=Which room do you want to venture into?
#VoteEffect.java
lblVote=Votar
lblCurrentVote=Votos actuales
lblVotedFor=votó por {0}
lblHowManyAdditionalVotesDoYouWant=¿Cuántos votos adicionales quieres?
#InputPayMana.java
lblChooseManaAbility=Elige una habilidad de maná:

View File

@@ -2091,6 +2091,7 @@ lblChooseRoom=Dans quelle pièce voulez-vous vous aventurer ?
#VoteEffect.java
lblVote=Voter
lblCurrentVote=Voix actuelles
lblVotedFor=a voté pour {0}
lblHowManyAdditionalVotesDoYouWant=Combien de votes supplémentaires souhaitez-vous ?
#VDevMenu.java
lblUnlimitedLands=Jouer des terrains illimités

View File

@@ -2086,6 +2086,7 @@ lblChooseRoom=Which room do you want to venture into?
#VoteEffect.java
lblVote=Voto
lblCurrentVote=Voti attuali
lblVotedFor=ha votato per {0}
lblHowManyAdditionalVotesDoYouWant=Quanti voti aggiuntivi vuoi?
#InputPayMana.java
lblChooseManaAbility=Scegli una abilità di mana:

View File

@@ -2086,6 +2086,7 @@ lblChooseRoom=どの部屋を探索しますか?
#VoteEffect.java
lblVote=投票
lblCurrentVote=現在の投票
lblVotedFor=は{0}に投票しました
lblHowManyAdditionalVotesDoYouWant=追加に何票を投票します?
#InputPayMana.java
lblChooseManaAbility=マナ能力を選択:

View File

@@ -2148,6 +2148,7 @@ lblChooseRoom=Qual sala você quer se aventurar?
#VoteEffect.java
lblVote=Vote
lblCurrentVote=Votos Atuais
lblVotedFor=votou em {0}
lblHowManyAdditionalVotesDoYouWant=Quantos votos adicionais você quer?
#VDevMenu.java
lblUnlimitedLands=Jogar Terrenos Ilimitados

View File

@@ -2091,6 +2091,7 @@ lblChooseRoom=你想要进入哪个房间探险?
#VoteEffect.java
lblVote=投票
lblCurrentVote=当前投票
lblVotedFor=投票给了{0}
lblHowManyAdditionalVotesDoYouWant=你想要额外投多少票?
#VDevMenu.java
lblUnlimitedLands=使用地不受限制