Merge pull request #2959 from Northmoc/ichor

MOC: Ichor Elixir + support
This commit is contained in:
Anthony Calosa
2023-04-21 11:05:08 +08:00
committed by GitHub
29 changed files with 299 additions and 121 deletions

View File

@@ -1,20 +1,11 @@
package forge.ai;
import java.security.InvalidParameterException;
import java.util.*;
import forge.game.keyword.Keyword;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import forge.LobbyPlayer;
import forge.ai.ability.ProtectAi;
import forge.card.CardStateName;
@@ -25,48 +16,26 @@ import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard;
import forge.deck.Deck;
import forge.deck.DeckSection;
import forge.game.Game;
import forge.game.GameEntity;
import forge.game.GameObject;
import forge.game.GameType;
import forge.game.*;
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.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil;
import forge.game.card.CardView;
import forge.game.card.CounterType;
import forge.game.combat.Combat;
import forge.game.cost.Cost;
import forge.game.cost.CostEnlist;
import forge.game.cost.CostPart;
import forge.game.cost.CostPartMana;
import forge.game.keyword.Keyword;
import forge.game.keyword.KeywordInterface;
import forge.game.mana.Mana;
import forge.game.mana.ManaConversionMatrix;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.DelayedReveal;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.player.PlayerController;
import forge.game.player.PlayerView;
import forge.game.player.*;
import forge.game.replacement.ReplacementEffect;
import forge.game.spellability.Ability;
import forge.game.spellability.AbilityStatic;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.LandAbility;
import forge.game.spellability.OptionalCost;
import forge.game.spellability.OptionalCostValue;
import forge.game.spellability.Spell;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.TargetChoices;
import forge.game.spellability.*;
import forge.game.trigger.WrappedAbility;
import forge.game.zone.ZoneType;
import forge.item.PaperCard;
@@ -75,6 +44,12 @@ import forge.util.ITriggerEvent;
import forge.util.MyRandom;
import forge.util.collect.FCollection;
import forge.util.collect.FCollectionView;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import java.security.InvalidParameterException;
import java.util.*;
/**
@@ -606,6 +581,12 @@ public class PlayerControllerAi extends PlayerController {
return Aggregates.random(sectors);
}
@Override
public PlanarDice choosePDRollToIgnore(List<PlanarDice> rolls) {
//TODO create AI logic for this
return Aggregates.random(rolls);
}
@Override
public boolean mulliganKeepHand(Player firstPlayer, int cardsToReturn) {
return !ComputerUtil.wantMulligan(player, cardsToReturn);

View File

@@ -134,7 +134,7 @@ public class RollPlanarDiceAi extends SpellAbilityAi {
decideToRoll = false;
}
if (ai.getGame().getPhaseHandler().getPlanarDiceRolledthisTurn() >= maxActivations) {
if (ai.getGame().getPhaseHandler().getPlanarDiceSpecialActionThisTurn() >= maxActivations) {
decideToRoll = false;
}

View File

@@ -212,6 +212,13 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
if (ArrayUtils.contains(valids, o)) {
return true;
}
} else if (o instanceof PlanarDice) {
for (String s : valids) {
PlanarDice valid = PlanarDice.smartValueOf(s);
if (((PlanarDice) o).name().equals(valid.name())) {
return true;
}
}
}
return false;

View File

@@ -28,8 +28,7 @@ public enum GlobalRuleChange {
noNight ("It can't become night."),
onlyOneBlocker ("No more than one creature can block each combat."),
onlyOneBlockerPerOpponent ("Each opponent can't block with more than one creature."),
onlyTwoBlockers ("No more than two creatures can block each combat."),
blankIsChaos("Each blank roll of the planar dice is a {CHAOS} roll.");
onlyTwoBlockers ("No more than two creatures can block each combat.");
private final String ruleText;

View File

@@ -1,15 +1,16 @@
package forge.game;
import java.util.Arrays;
import java.util.Map;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import forge.game.ability.AbilityKey;
import forge.game.event.GameEventRollDie;
import forge.game.player.Player;
import forge.game.replacement.ReplacementType;
import forge.game.trigger.TriggerType;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* Represents the planar dice for Planechase games.
*
@@ -20,36 +21,68 @@ public enum PlanarDice {
Blank;
public static PlanarDice roll(Player roller, PlanarDice riggedResult) {
PlanarDice res = Blank;
final Game game = roller.getGame();
int rolls = 1;
int ignore = 0;
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(roller);
repParams.put(AbilityKey.Number, rolls);
repParams.put(AbilityKey.Ignore, ignore);
switch (game.getReplacementHandler().run(ReplacementType.RollPlanarDice, repParams)) {
case NotReplaced:
break;
case Updated: {
rolls = (int) repParams.get(AbilityKey.Number);
ignore = (int) repParams.get(AbilityKey.Ignore);
break;
}
}
List<PlanarDice> results = Lists.newArrayList();
for (int r = 0; r < rolls; r++) {
PlanarDice thisRoll = Blank;
int i = forge.util.MyRandom.getRandom().nextInt(6);
// Play the die roll sound
roller.getGame().fireEvent(new GameEventRollDie());
roller.roll();
if (riggedResult != null)
res = riggedResult;
thisRoll = riggedResult;
else if (i == 0)
res = Planeswalk;
thisRoll = Planeswalk;
else if (i == 1)
res = Chaos;
thisRoll = Chaos;
results.add(thisRoll);
}
for (int ig = 0; ig < ignore; ig++) {
results.remove(roller.getController().choosePDRollToIgnore(results));
}
PlanarDice res = results.get(0);
PlanarDice trigRes = res;
if(roller.getGame().getStaticEffects().getGlobalRuleChange(GlobalRuleChange.blankIsChaos)
&& res == Blank)
{
trigRes = Chaos;
final Map<AbilityKey, Object> resRepParams = AbilityKey.mapFromAffected(roller);
resRepParams.put(AbilityKey.Result, res);
switch (game.getReplacementHandler().run(ReplacementType.PlanarDiceResult, resRepParams)) {
case NotReplaced:
break;
case Updated: {
trigRes = (PlanarDice) resRepParams.get(AbilityKey.Result);
break;
}
}
Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(roller);
runParams.put(AbilityKey.Result, trigRes);
roller.getGame().getTriggerHandler().runTrigger(TriggerType.PlanarDice, runParams,false);
game.getTriggerHandler().runTrigger(TriggerType.PlanarDice, runParams,false);
// Also run normal RolledDie and RolledDieOnce triggers
for (int r = 0; r < rolls; r++) {
runParams = AbilityKey.mapFromPlayer(roller);
runParams.put(AbilityKey.Sides, 6);
runParams.put(AbilityKey.Result, 0);
roller.getGame().getTriggerHandler().runTrigger(TriggerType.RolledDie, runParams, false);
}
runParams = AbilityKey.mapFromPlayer(roller);
runParams.put(AbilityKey.Sides, 6);

View File

@@ -74,6 +74,7 @@ public enum AbilityKey {
FirstTime("FirstTime"),
Fizzle("Fizzle"),
FoundSearchingLibrary("FoundSearchingLibrary"),
Ignore("Ignore"),
IsCombat("IsCombat"), // TODO confirm that this and IsCombatDamage can be merged
IsCombatDamage("IsCombatDamage"),
IsDamage("IsDamage"),

View File

@@ -2690,8 +2690,8 @@ public class AbilityUtils {
return doXMath(game.getStack().getSpellsCastThisTurn().size() - 1, expr, c, ctb);
}
if (sq[0].startsWith("RolledThisTurn")) {
return game.getPhaseHandler().getPlanarDiceRolledthisTurn();
if (sq[0].startsWith("PlanarDiceSpecialActionThisTurn")) {
return game.getPhaseHandler().getPlanarDiceSpecialActionThisTurn();
}
if (sq[0].contains("CardTypes")) {

View File

@@ -4,6 +4,7 @@ import java.util.List;
import java.util.Map;
import forge.game.GameObject;
import forge.game.PlanarDice;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
@@ -41,6 +42,8 @@ public class ReplaceEffect extends SpellAbilityEffect {
if (list.size() > 0) {
params.put(varName, list.get(0));
}
} else if ("PlanarDice".equals(type)) {
params.put(varName, PlanarDice.smartValueOf(varValue));
} else {
params.put(varName, AbilityUtils.calculateAmount(card, varValue, sa));
}

View File

@@ -19,17 +19,19 @@ public class RollPlanarDiceEffect extends SpellAbilityEffect {
*/
@Override
public void resolve(SpellAbility sa) {
boolean countedTowardsCost = !sa.hasParam("NotCountedTowardsCost");
final Player activator = sa.getActivatingPlayer();
final Game game = activator.getGame();
if(countedTowardsCost) {
game.getPhaseHandler().incPlanarDiceRolledthisTurn();
if (game.getActivePlanes() == null) { // not a planechase game, nothing happens
return;
}
if (sa.hasParam("SpecialAction")) {
game.getPhaseHandler().incPlanarDiceSpecialActionThisTurn();
}
PlanarDice result = PlanarDice.roll(activator, null);
// Play the die roll sound
activator.getGame().fireEvent(new GameEventRollDie());
String message = Localizer.getInstance().getMessage("lblPlayerRolledResult", activator.getName(), result.toString());
game.fireEvent(new GameEventRollDie());
PlanarDice result = PlanarDice.roll(activator, null);
String message = Localizer.getInstance().getMessage("lblPlanarDiceResult", result.toString());
game.getAction().notifyOfValue(sa, activator, message, null);
}

View File

@@ -341,23 +341,21 @@ public class CardFactory {
}
private static void buildPlaneAbilities(Card card) {
StringBuilder triggerSB = new StringBuilder();
triggerSB.append("Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Secondary$ True | ");
triggerSB.append("TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, ");
triggerSB.append("then move the top card of your planar deck off that planar deck and turn it face up");
String trigger = "Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Secondary$ True | " +
"TriggerDescription$ Whenever you roll the Planeswalker symbol on the planar die, planeswalk.";
String rolledWalk = "DB$ Planeswalk";
Trigger planesWalkTrigger = TriggerHandler.parseTrigger(triggerSB.toString(), card, true);
Trigger planesWalkTrigger = TriggerHandler.parseTrigger(trigger, card, true);
planesWalkTrigger.setOverridingAbility(AbilityFactory.getAbility(rolledWalk, card));
card.addTrigger(planesWalkTrigger);
StringBuilder saSB = new StringBuilder();
saSB.append("AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | Activator$ Player | ActivationZone$ Command | ");
saSB.append("SpellDescription$ Roll the planar dice. X is equal to the amount of times the planar die has been rolled this turn.");
String specialA = "ST$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | Activator$ Player | SpecialAction$ True" +
" | ActivationZone$ Command | SpellDescription$ Roll the planar dice. X is equal to the number of " +
"times you have previously taken this action this turn.";
SpellAbility planarRoll = AbilityFactory.getAbility(saSB.toString(), card);
planarRoll.setSVar("X", "Count$RolledThisTurn");
SpellAbility planarRoll = AbilityFactory.getAbility(specialA, card);
planarRoll.setSVar("X", "Count$PlanarDiceSpecialActionThisTurn");
card.addSpellAbility(planarRoll);
}

View File

@@ -91,7 +91,7 @@ public class PhaseHandler implements java.io.Serializable {
private int nUpkeepsThisGame = 0;
private int nCombatsThisTurn = 0;
private int nMain2sThisTurn = 0;
private int planarDiceRolledthisTurn = 0;
private int planarDiceSpecialActionThisTurn = 0;
private transient Player playerTurn = null;
private transient Player playerPreviousTurn = null;
@@ -522,7 +522,7 @@ public class PhaseHandler implements java.io.Serializable {
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(playerTurn);
game.getTriggerHandler().runTrigger(TriggerType.TurnBegin, runParams, false);
}
planarDiceRolledthisTurn = 0;
planarDiceSpecialActionThisTurn = 0;
// Play the End Turn sound
game.fireEvent(new GameEventTurnEnded());
break;
@@ -1212,11 +1212,11 @@ public class PhaseHandler implements java.io.Serializable {
onPhaseBegin();
}
public int getPlanarDiceRolledthisTurn() {
return planarDiceRolledthisTurn;
public int getPlanarDiceSpecialActionThisTurn() {
return planarDiceSpecialActionThisTurn;
}
public void incPlanarDiceRolledthisTurn() {
planarDiceRolledthisTurn++;
public void incPlanarDiceSpecialActionThisTurn() {
planarDiceSpecialActionThisTurn++;
}
public String debugPrintState(boolean hasPriority) {

View File

@@ -5,6 +5,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import forge.game.*;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
@@ -19,13 +20,7 @@ import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard;
import forge.deck.Deck;
import forge.deck.DeckSection;
import forge.game.Game;
import forge.game.GameEntity;
import forge.game.GameObject;
import forge.game.GameOutcome.AnteResult;
import forge.game.GameType;
import forge.game.GameView;
import forge.game.Match;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
@@ -192,6 +187,8 @@ public abstract class PlayerController {
return chooseSector(assignee, ai, sectors);
}
public abstract PlanarDice choosePDRollToIgnore(List<PlanarDice> rolls);
public abstract Object vote(SpellAbility sa, String prompt, List<Object> options, ListMultimap<Object, Player> votes, Player forPlayer);
public abstract CardCollectionView getCardsToMulligan(Player firstPlayer);

View File

@@ -0,0 +1,56 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.game.replacement;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
import java.util.Map;
public class ReplacePlanarDiceResult extends ReplacementEffect {
/**
* Instantiates a new replace roll planar dice.
*
* @param params the params
* @param host the host
*/
public ReplacePlanarDiceResult(final Map<String, String> params, final Card host, final boolean intrinsic) {
super(params, host, intrinsic);
}
/* (non-Javadoc)
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
public boolean canReplace(Map<AbilityKey, Object> runParams) {
if (!matchesValidParam("ValidRoll", runParams.get(AbilityKey.Result))) {
return false;
}
return true;
}
/* (non-Javadoc)
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.Map, forge.card.spellability.SpellAbility)
*/
@Override
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
sa.setReplacingObject(AbilityKey.Result, runParams.get(AbilityKey.Result));
}
}

View File

@@ -0,0 +1,57 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.game.replacement;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
import java.util.Map;
public class ReplaceRollPlanarDice extends ReplacementEffect {
/**
* Instantiates a new replace roll planar dice.
*
* @param params the params
* @param host the host
*/
public ReplaceRollPlanarDice(final Map<String, String> params, final Card host, final boolean intrinsic) {
super(params, host, intrinsic);
}
/* (non-Javadoc)
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
public boolean canReplace(Map<AbilityKey, Object> runParams) {
if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Affected))) {
return false;
}
return true;
}
/* (non-Javadoc)
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.Map, forge.card.spellability.SpellAbility)
*/
@Override
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
sa.setReplacingObject(AbilityKey.Number, runParams.get(AbilityKey.Number));
sa.setReplacingObject(AbilityKey.Ignore, runParams.get(AbilityKey.Ignore));
}
}

View File

@@ -33,8 +33,10 @@ public enum ReplacementType {
LoseMana(ReplaceLoseMana.class),
Mill(ReplaceMill.class),
Moved(ReplaceMoved.class),
PlanarDiceResult(ReplacePlanarDiceResult.class),
ProduceMana(ReplaceProduceMana.class),
Proliferate(ReplaceProliferate.class),
RollPlanarDice(ReplaceRollPlanarDice.class),
Scry(ReplaceScry.class),
SetInMotion(ReplaceSetInMotion.class),
Surveil(ReplaceSurveil.class),

View File

@@ -68,6 +68,7 @@ public class MessageUtil {
case Protection:
return Localizer.getInstance().getMessage("lblPlayerChooseValue", choser, value);
case RollDice:
case RollPlanarDice:
case PutCounter:// For Clay Golem cost text
return value;
case Vote:

View File

@@ -20,10 +20,7 @@ import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard;
import forge.deck.Deck;
import forge.deck.DeckSection;
import forge.game.Game;
import forge.game.GameEntity;
import forge.game.GameObject;
import forge.game.GameType;
import forge.game.*;
import forge.game.ability.AbilityUtils;
import forge.game.card.*;
import forge.game.combat.Combat;
@@ -503,6 +500,11 @@ public class PlayerControllerForTests extends PlayerController {
return chooseItem(sectors);
}
@Override
public PlanarDice choosePDRollToIgnore(List<PlanarDice> rolls) {
return Aggregates.random(rolls);
}
@Override
public Object vote(SpellAbility sa, String prompt, List<Object> options, ListMultimap<Object, Player> votes, Player forPlayer) {
return chooseItem(options);

View File

@@ -1,10 +1,11 @@
Name:Chaotic Aether
ManaCost:no cost
Types:Phenomenon
T:Mode$ PlaneswalkedTo | ValidCard$ Card.Self | Execute$ Aether | TriggerDescription$ When you encounter CARDNAME, each blank roll of the planar dice is a {CHAOS} roll until a player planeswalks away from a plane. (Then planeswalk away from this phenomenon)
SVar:Aether:DB$ Effect | Name$ Chaotic Aether Effect | StaticAbilities$ STBlankIsChaos | Triggers$ TPWAway | SubAbility$ PWAway
SVar:PWAway:DB$ Planeswalk | Cost$ 0
SVar:STBlankIsChaos:Mode$ Continuous | EffectZone$ Command | GlobalRule$ Each blank roll of the planar dice is a {CHAOS} roll.
SVar:TPWAway:Mode$ PlaneswalkedFrom | ValidCard$ Plane | Execute$ ExileSelf | Static$ True | TriggerDescription$ Until a player planeswalks away from a plane, each blank roll of the planar dice is a {CHAOS} roll.
T:Mode$ PlaneswalkedTo | ValidCard$ Card.Self | Execute$ Aether | TriggerDescription$ When you encounter CARDNAME, each blank roll of the planar dice is a {CHAOS} roll until a player planeswalks away from a plane. (Then planeswalk away from this phenomenon.)
SVar:Aether:DB$ Effect | ReplacementEffects$ BlankIsChaos | Triggers$ TPWAway | SubAbility$ PWAway
SVar:PWAway:DB$ Planeswalk
SVar:BlankIsChaos:Event$ PlanarDiceResult | ValidRoll$ Blank | ReplaceWith$ REChaos | Description$ Each blank roll of the planar die is a {CHAOS} roll until a player planeswalks away from a plane.
SVar:REChaos:DB$ ReplaceEffect | VarName$ Result | VarValue$ Chaos | VarType$ PlanarDice
SVar:TPWAway:Mode$ PlaneswalkedFrom | ValidCard$ Plane | Execute$ ExileSelf | Static$ True
SVar:ExileSelf:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
Oracle:When you encounter Chaotic Aether, each blank roll of the planar die is a CHAOS roll until a player planeswalks away from a plane. (Then planeswalk away from this phenomenon.)
Oracle:When you encounter Chaotic Aether, each blank roll of the planar die is a {CHAOS} roll until a player planeswalks away from a plane. (Then planeswalk away from this phenomenon.)

View File

@@ -1,7 +1,7 @@
Name:Krosa
ManaCost:no cost
Types:Plane Dominaria
S:Mode$ Continuous | EffectZone$ Command | Affected$ Creature | AddPower$ 2 | AddToughness$ 2 | Description$ All Creatures get +2/+2.
S:Mode$ Continuous | EffectZone$ Command | Affected$ Creature | AddPower$ 2 | AddToughness$ 2 | Description$ All creatures get +2/+2.
T:Mode$ PlanarDice | Result$ Chaos | OptionalDecider$ You | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll {CHAOS}, you may add {W}{U}{B}{R}{G}.
SVar:RolledChaos:DB$ Mana | Produced$ W U B R G
SVar:AIRollPlanarDieParams:Mode$ Always | RollInMain1$ True

View File

@@ -0,0 +1,8 @@
Name:Ichor Elixir
ManaCost:4
Types:Artifact
R:Event$ RollPlanarDice | ValidPlayer$ You | ReplaceWith$ PlusRoll | Description$ If you would roll one or more planar dice, instead roll that many planar dice plus one and ignore one.
SVar:PlusRoll:DB$ ReplaceEffect | VarName$ Number | VarValue$ ReplaceCount$Number/Plus.1 | SubAbility$ IgnoreRoll
SVar:IgnoreRoll:DB$ ReplaceEffect | VarName$ Ignore | VarValue$ ReplaceCount$Ignore/Plus.1
A:AB$ Mana | Cost$ T | Produced$ C | Amount$ 2 | SpellDescription$ Add {C}{C}.
Oracle:If you would roll one or more planar dice, instead roll that many planar dice plus one and ignore one.\n{T}: Add {C}{C}.

View File

@@ -1351,6 +1351,7 @@ lblLibrary=Bibliothek
lblGraveyard=Friedhof
lblAssignSectorCreature=Weise {0} einem Bereich zu
lblChooseSectorEffect=Wähle Bereich
lblChooseRollIgnore=Choose a roll to ignore
lblTop=Oben drauf
lblBottom=Unten drunter
lblNColorManaFromCard={0} {1} Mana von {2}
@@ -2042,8 +2043,10 @@ lblDoyouWantShuffleTheLibrary=Möchtest du deine Bibliothek mischen?
lblDoYouWantRepeatProcessAgain=Möchtest du den Vorgang wiederholen?
#RevealHandEffect.java
lblDoYouWantRevealYourHand=Möchtest du deine Handkarten offen vorzeigen?
#RollDiceEffect.java
lblPlayerRolledResult={0} würfelt {1}
#RollPlanarDiceEffect.java
lblPlayerRolledResult={0} würfelte {1}?
lblPlanarDiceResult=Planar dice result: {0}
#SacrificeEffect.java
lblDoYouWantPayEcho=Möchtest du die Echokosten zahlen
lblPayEcho=Zahle Echokosten

View File

@@ -1357,6 +1357,7 @@ lblLibrary=Library
lblGraveyard=Graveyard
lblAssignSectorCreature=Assign {0} to a sector
lblChooseSectorEffect=Choose a sector
lblChooseRollIgnore=Choose a roll to ignore
lblTop=Top
lblBottom=Bottom
lblNColorManaFromCard={0} {1} mana from {2}
@@ -2048,8 +2049,10 @@ lblDoyouWantShuffleTheLibrary=Do you want to shuffle the library?
lblDoYouWantRepeatProcessAgain=Do you want to repeat this process again?
#RevealHandEffect.java
lblDoYouWantRevealYourHand=Do you want to reveal your hand?
#RollPlanarDiceEffect.java
#RollDiceEffect.java
lblPlayerRolledResult={0} rolled {1}
#RollPlanarDiceEffect.java
lblPlanarDiceResult=Planar dice result: {0}
#SacrificeEffect.java
lblDoYouWantPayEcho=Do you want to pay Echo
lblPayEcho=Pay Echo

View File

@@ -1352,6 +1352,7 @@ lblLibrary=Biblioteca
lblGraveyard=Cementerio
lblAssignSectorCreature=Assign {0} to a sector
lblChooseSectorEffect=Choose a sector
lblChooseRollIgnore=Choose a roll to ignore
lblTop=Superior
lblBottom=Fondo
lblNColorManaFromCard={0} {1} maná de {2}
@@ -2043,8 +2044,10 @@ lblDoyouWantShuffleTheLibrary=¿Quieres barajar la biblioteca?
lblDoYouWantRepeatProcessAgain=¿Quiere repetir este proceso de nuevo?
#RevealHandEffect.java
lblDoYouWantRevealYourHand=¿Quieres descubrir tu mano?
#RollPlanarDiceEffect.java
#RollDiceEffect.java
lblPlayerRolledResult={0} lanzó {1}
#RollPlanarDiceEffect.java
lblPlanarDiceResult=Planar dice result: {0}
#SacrificeEffect.java
lblDoYouWantPayEcho=¿Quieres pagar Eco
lblPayEcho=Pagar Eco

View File

@@ -1294,7 +1294,7 @@ lblError=Erreur
lblWinGame=Gagner la partie
lblSetLifetoWhat=Mettre la vie à quoi ?
lblSetLifeforWhichPlayer=Définir la vie pour quel joueur
kglChoosePermanentstoTap=Choisir les permanents à engager
lblChoosePermanentstoTap=Choisir les permanents à engager
lblChoosePermanentstoUntap=Choisir les permanents à dégager
lblWhichTypeofCounter=Quel type de marqueur ?
lblHowManyCounters=Combien de marqueurs ?
@@ -1311,7 +1311,7 @@ lblSelectOrderForSimultaneousAbilities=Sélectionner l''ordre pour les capacité
lblReorderSimultaneousAbilities=Réorganiser les capacités simultanées
lblResolveFirst=Résoudre en premier
lblMoveCardstoToporBbottomofLibrary=Déplacer les cartes en haut ou en bas de la bibliothèque
lblSelectCardsToBeOutOnTheBottomOfYourLibrary=S\u00e9lectionnez les cartes \u00e0 mettre en bas de votre biblioth\u00e8que
lblSelectCardsToBeOutOnTheBottomOfYourLibrary=Sélectionnez les cartes à mettre en bas de votre bibliothèque
lblCardsToPutOnTheBottom=Cartes à mettre en bas
lblArrangeCardsToBePutOnTopOfYourLibrary=Disposer les cartes à mettre au-dessus de votre bibliothèque
lblTopOfLibrary=Haut de la bibliothèque
@@ -1353,18 +1353,20 @@ lblThereNoCardInPlayerZone=Il n''y a pas de cartes dans {0} {1}
lblPutCardsOnTheTopLibraryOrGraveyard=Placer {0} au-dessus de la bibliothèque ou du cimetière ?
lblLibrary=Bibliothèque
lblGraveyard=Cimetière
lblHaut=Haut
lblBas=Bas
lblAssignSectorCreature=Assign {0} to a sectorlblChooseSectorEffect=Choose a sector
lblChooseRollIgnore=Choose a roll to ignore
lblTop=Haut
lblBottom=Bas
lblNColorManaFromCard={0} {1} mana de {2}
lblPayManaFromManaPool=Payer le mana du pool de mana
lblChooseATargetType=Choisir un type {0}
lblUntap=Dégager
lblOdds=Cote
lblPairs=Pairs
lblEvens=Pairs
lblLeaveTapped=Laisser tapé
lblUntapAndSkipThisTurn=Dégager (et sauter ce tour)
lblGauche=Gauche
lblDroite=Droite
lblLeft=Gauche
lblRight=Droite
lblAddCounter=Ajouter un marqueur
lblRemoveCounter=Supprimer le marqueur
lblWinTheFlip=gagner le flip
@@ -2045,8 +2047,10 @@ lblDoyouWantShuffleTheLibrary=Voulez-vous mélanger la bibliothèque ?
lblDoYouWantRepeatProcessAgain=Voulez-vous répéter ce processus à nouveau ?
#RevealHandEffect.java
lblDoYouWantRevealYourHand=Voulez-vous révéler votre main ?
#RollPlanarDiceEffect.java
#RollDiceEffect.java
lblPlayerRolledResult={0} a lancé {1}
#RollPlanarDiceEffect.java
lblPlanarDiceResult=Planar dice result: {0}
#SacrificeEffect.java
lblDoYouWantPayEcho=Voulez-vous payer Echo
lblPayEcho=Écho de paiement

View File

@@ -1352,6 +1352,7 @@ lblLibrary=Grimorio
lblGraveyard=Cimitero
lblAssignSectorCreature=Assign {0} to a sector
lblChooseSectorEffect=Choose a sector
lblChooseRollIgnore=Choose a roll to ignore
lblTop=Cima
lblBottom=Fondo
lblNColorManaFromCard={0} {1} mana da {2}
@@ -2042,8 +2043,10 @@ lblDoyouWantShuffleTheLibrary=Vuoi mescolare il grimorio?
lblDoYouWantRepeatProcessAgain=Vuoi ripetere nuovamente questo procedimento?
#RevealHandEffect.java
lblDoYouWantRevealYourHand=Vuoi rivelare la tua mano?
#RollPlanarDiceEffect.java
#RollDiceEffect.java
lblPlayerRolledResult={0} ha ottenuto {1} col dado
#RollPlanarDiceEffect.java
lblPlanarDiceResult=Planar dice result: {0}
#SacrificeEffect.java
lblDoYouWantPayEcho=Vuoi pagare Eco
lblPayEcho=Paga Eco

View File

@@ -1353,6 +1353,7 @@ lblLibrary=ライブラリー
lblGraveyard=墓地
lblAssignSectorCreature=Assign {0} to a sector
lblChooseSectorEffect=Choose a sector
lblChooseRollIgnore=Choose a roll to ignore
lblTop=タップ
lblBottom=ボトム
lblNColorManaFromCard={2}から {0} {1} のマナ
@@ -2042,8 +2043,10 @@ lblDoyouWantShuffleTheLibrary=ライブラリーをシャッフルしますか
lblDoYouWantRepeatProcessAgain=この手順をもう一度しますか?
#RevealHandEffect.java
lblDoYouWantRevealYourHand=手札を公開しますか?
#RollPlanarDiceEffect.java
#RollDiceEffect.java
lblPlayerRolledResult={0}が {1}をロールしました
#RollPlanarDiceEffect.java
lblPlanarDiceResult=Planar dice result: {0}
#SacrificeEffect.java
lblDoYouWantPayEcho=エコーコストを支払いますか:
lblPayEcho=エコーコストを支払います

View File

@@ -1383,6 +1383,7 @@ lblLibrary=Grimório
lblGraveyard=Cemitério
lblAssignSectorCreature=Assign {0} to a sector
lblChooseSectorEffect=Choose a sector
lblChooseRollIgnore=Choose a roll to ignore
lblTop=Topo
lblBottom=Fundo
lblNColorManaFromCard={0} {1} mana de {2}
@@ -2104,8 +2105,10 @@ lblDoyouWantShuffleTheLibrary=Quer embaralhar o grimório?
lblDoYouWantRepeatProcessAgain=Quer repetir este processo novamente?
#RevealHandEffect.java
lblDoYouWantRevealYourHand=Você quer revelar sua mão?
#RollPlanarDiceEffect.java
#RollDiceEffect.java
lblPlayerRolledResult={0} tirou {1}
#RollPlanarDiceEffect.java
lblPlanarDiceResult=Planar dice result: {0}
#SacrificeEffect.java
lblDoYouWantPayEcho=Quer pagar pelo Eco
lblPayEcho=Pagar Eco

View File

@@ -1354,6 +1354,7 @@ lblLibrary=牌库
lblGraveyard=坟场
lblAssignSectorCreature=将{0}分配给一部分
lblChooseSectorEffect=选择一部分
lblChooseRollIgnore=Choose a roll to ignore
lblTop=
lblBottom=
lblNColorManaFromCard={2}产{0}个{1}法术力
@@ -2046,8 +2047,10 @@ lblDoyouWantShuffleTheLibrary=你想要洗这个牌库吗?
lblDoYouWantRepeatProcessAgain=你是否想再次重复这个过程?
#RevealHandEffect.java
lblDoYouWantRevealYourHand=你想展示你的手牌吗?
#RollPlanarDiceEffect.java
#RollDiceEffect.java
lblPlayerRolledResult={0}掷骰结果为{1}
#RollPlanarDiceEffect.java
lblPlanarDiceResult=Planar dice result: {0}
#SacrificeEffect.java
lblDoYouWantPayEcho=你想支付返响费用
lblPayEcho=支付返响费用

View File

@@ -1391,6 +1391,11 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
return getGui().one(prompt, sectors);
}
@Override
public PlanarDice choosePDRollToIgnore(List<PlanarDice> rolls) {
return getGui().one(Localizer.getInstance().getMessage("lblChooseRollIgnore"), rolls);
}
@Override
public Object vote(final SpellAbility sa, final String prompt, final List<Object> options,
final ListMultimap<Object, Player> votes, Player forPlayer) {