mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-11 16:26:22 +00:00
Secret Council mechanic and cards (#3542)
This commit is contained in:
@@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)")) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
13
forge-gui/res/cardsfolder/upcoming/cirdan_the_shipwright.txt
Normal file
13
forge-gui/res/cardsfolder/upcoming/cirdan_the_shipwright.txt
Normal 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.
|
||||
@@ -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.
|
||||
@@ -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.)
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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á:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -2086,6 +2086,7 @@ lblChooseRoom=どの部屋を探索しますか?
|
||||
#VoteEffect.java
|
||||
lblVote=投票
|
||||
lblCurrentVote=現在の投票
|
||||
lblVotedFor=は{0}に投票しました
|
||||
lblHowManyAdditionalVotesDoYouWant=追加に何票を投票します?
|
||||
#InputPayMana.java
|
||||
lblChooseManaAbility=マナ能力を選択:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2091,6 +2091,7 @@ lblChooseRoom=你想要进入哪个房间探险?
|
||||
#VoteEffect.java
|
||||
lblVote=投票
|
||||
lblCurrentVote=当前投票
|
||||
lblVotedFor=投票给了{0}
|
||||
lblHowManyAdditionalVotesDoYouWant=你想要额外投多少票?
|
||||
#VDevMenu.java
|
||||
lblUnlimitedLands=使用地不受限制
|
||||
|
||||
Reference in New Issue
Block a user