PIP: Radiation mechanic implementation (#4204)

* PIP: Radiation mechanic implementation

* remove OVERRIDE

* remove unused property
This commit is contained in:
Northmoc
2023-12-25 22:55:14 -05:00
committed by GitHub
parent 08b8d7deec
commit 7f5e75bdb0
39 changed files with 359 additions and 137 deletions

View File

@@ -338,14 +338,14 @@ public class PlayerControllerAi extends PlayerController {
} }
@Override @Override
public void reveal(CardCollectionView cards, ZoneType zone, Player owner, String messagePrefix) { public void reveal(CardCollectionView cards, ZoneType zone, Player owner, String messagePrefix, boolean addSuffix) {
for (Card c : cards) { for (Card c : cards) {
AiCardMemory.rememberCard(player, c, AiCardMemory.MemorySet.REVEALED_CARDS); AiCardMemory.rememberCard(player, c, AiCardMemory.MemorySet.REVEALED_CARDS);
} }
} }
@Override @Override
public void reveal(List<CardView> cards, ZoneType zone, PlayerView owner, String messagePrefix) { public void reveal(List<CardView> cards, ZoneType zone, PlayerView owner, String messagePrefix, boolean addSuffix) {
for (CardView cv : cards) { for (CardView cv : cards) {
AiCardMemory.rememberCard(player, player.getGame().findByView(cv), AiCardMemory.MemorySet.REVEALED_CARDS); AiCardMemory.rememberCard(player, player.getGame().findByView(cv), AiCardMemory.MemorySet.REVEALED_CARDS);
} }

View File

@@ -139,6 +139,7 @@ public enum SpellApiToAi {
.put(ApiType.PumpAll, PumpAllAi.class) .put(ApiType.PumpAll, PumpAllAi.class)
.put(ApiType.PutCounter, CountersPutAi.class) .put(ApiType.PutCounter, CountersPutAi.class)
.put(ApiType.PutCounterAll, CountersPutAllAi.class) .put(ApiType.PutCounterAll, CountersPutAllAi.class)
.put(ApiType.Radiation, AlwaysPlayAi.class)
.put(ApiType.RearrangeTopOfLibrary, RearrangeTopOfLibraryAi.class) .put(ApiType.RearrangeTopOfLibrary, RearrangeTopOfLibraryAi.class)
.put(ApiType.Regenerate, RegenerateAi.class) .put(ApiType.Regenerate, RegenerateAi.class)
.put(ApiType.RegenerateAll, RegenerateAllAi.class) .put(ApiType.RegenerateAll, RegenerateAllAi.class)

View File

@@ -1926,15 +1926,15 @@ public class GameAction {
revealTo(cards, to, null); revealTo(cards, to, null);
} }
public void revealTo(final CardCollectionView cards, final Player to, String messagePrefix) { public void revealTo(final CardCollectionView cards, final Player to, String messagePrefix) {
revealTo(cards, Collections.singleton(to), messagePrefix); revealTo(cards, Collections.singleton(to), messagePrefix, true);
} }
public void revealTo(final Card card, final Iterable<Player> to) { public void revealTo(final Card card, final Iterable<Player> to) {
revealTo(new CardCollection(card), to); revealTo(new CardCollection(card), to);
} }
public void revealTo(final CardCollectionView cards, final Iterable<Player> to) { public void revealTo(final CardCollectionView cards, final Iterable<Player> to) {
revealTo(cards, to, null); revealTo(cards, to, null, true);
} }
public void revealTo(final CardCollectionView cards, final Iterable<Player> to, String messagePrefix) { public void revealTo(final CardCollectionView cards, final Iterable<Player> to, String messagePrefix, boolean addSuffix) {
if (cards.isEmpty()) { if (cards.isEmpty()) {
return; return;
} }
@@ -1942,7 +1942,7 @@ public class GameAction {
final ZoneType zone = cards.getFirst().getZone().getZoneType(); final ZoneType zone = cards.getFirst().getZone().getZoneType();
final Player owner = cards.getFirst().getOwner(); final Player owner = cards.getFirst().getOwner();
for (final Player p : to) { for (final Player p : to) {
p.getController().reveal(cards, zone, owner, messagePrefix); p.getController().reveal(cards, zone, owner, messagePrefix, addSuffix);
} }
} }
@@ -1953,18 +1953,25 @@ public class GameAction {
reveal(cards, cardOwner, dontRevealToOwner, null); reveal(cards, cardOwner, dontRevealToOwner, null);
} }
public void reveal(CardCollectionView cards, Player cardOwner, boolean dontRevealToOwner, String messagePrefix) { public void reveal(CardCollectionView cards, Player cardOwner, boolean dontRevealToOwner, String messagePrefix) {
reveal(cards, cardOwner, dontRevealToOwner, messagePrefix, true);
}
public void reveal(CardCollectionView cards, Player cardOwner, boolean dontRevealToOwner, String messagePrefix, boolean msgAddSuffix) {
Card firstCard = Iterables.getFirst(cards, null); Card firstCard = Iterables.getFirst(cards, null);
if (firstCard == null) { if (firstCard == null) {
return; return;
} }
reveal(cards, game.getZoneOf(firstCard).getZoneType(), cardOwner, dontRevealToOwner, messagePrefix); reveal(cards, game.getZoneOf(firstCard).getZoneType(), cardOwner, dontRevealToOwner, messagePrefix, msgAddSuffix);
} }
public void reveal(CardCollectionView cards, ZoneType zt, Player cardOwner, boolean dontRevealToOwner, String messagePrefix) { public void reveal(CardCollectionView cards, ZoneType zt, Player cardOwner, boolean dontRevealToOwner, String messagePrefix) {
reveal(cards, zt, cardOwner, dontRevealToOwner, messagePrefix, true);
}
public void reveal(CardCollectionView cards, ZoneType zt, Player cardOwner, boolean dontRevealToOwner, String messagePrefix, boolean msgAddSuffix) {
for (Player p : game.getPlayers()) { for (Player p : game.getPlayers()) {
if (dontRevealToOwner && cardOwner == p) { if (dontRevealToOwner && cardOwner == p) {
continue; continue;
} }
p.getController().reveal(cards, zt, cardOwner, messagePrefix); p.getController().reveal(cards, zt, cardOwner, messagePrefix, msgAddSuffix);
} }
} }

View File

@@ -10,6 +10,7 @@ import com.google.common.eventbus.Subscribe;
import forge.LobbyPlayer; import forge.LobbyPlayer;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CounterEnumType;
import forge.game.event.*; import forge.game.event.*;
import forge.game.event.GameEventCardDamaged.DamageType; import forge.game.event.GameEventCardDamaged.DamageType;
import forge.game.player.Player; import forge.game.player.Player;
@@ -224,6 +225,21 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
return new GameLogEntry(GameLogEntryType.DAMAGE, message); return new GameLogEntry(GameLogEntryType.DAMAGE, message);
} }
@Override
public GameLogEntry visit(GameEventPlayerRadiation ev) {
String message;
final int change = ev.change;
String radCtr = CounterEnumType.RAD.getName().toLowerCase() + " " +
Localizer.getInstance().getMessage("lblCounter").toLowerCase();
if (change >= 0) message = localizer.getMessage("lblLogPlayerRadiation",
ev.receiver.toString(), Lang.nounWithNumeralExceptOne(String.valueOf(change), radCtr),
ev.source.toString());
else message = localizer.getMessage("lblLogPlayerRadRemove",
ev.receiver.toString(), Lang.nounWithNumeralExceptOne(String.valueOf(Math.abs(change)), radCtr),
ev.source.toString());
return new GameLogEntry(GameLogEntryType.DAMAGE, message);
}
@Override @Override
public GameLogEntry visit(final GameEventAttackersDeclared ev) { public GameLogEntry visit(final GameEventAttackersDeclared ev) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();

View File

@@ -139,6 +139,7 @@ public enum ApiType {
PumpAll (PumpAllEffect.class), PumpAll (PumpAllEffect.class),
PutCounter (CountersPutEffect.class), PutCounter (CountersPutEffect.class),
PutCounterAll (CountersPutAllEffect.class), PutCounterAll (CountersPutAllEffect.class),
Radiation (RadiationEffect.class),
RearrangeTopOfLibrary (RearrangeTopOfLibraryEffect.class), RearrangeTopOfLibrary (RearrangeTopOfLibraryEffect.class),
Regenerate (RegenerateEffect.class), Regenerate (RegenerateEffect.class),
RegenerateAll (RegenerateAllEffect.class), RegenerateAll (RegenerateAllEffect.class),

View File

@@ -98,6 +98,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
return; return;
} }
boolean revealTitle = (sa.hasParam("RevealTitle"));
for (Player p : tgtPlayers) { for (Player p : tgtPlayers) {
if (!p.isInGame()) { if (!p.isInGame()) {
p = getNewChooser(sa, activator, p); p = getNewChooser(sa, activator, p);
@@ -267,14 +268,15 @@ public class ChooseCardEffect extends SpellAbilityEffect {
} }
} }
if (sa.hasParam("Reveal") && !sa.hasParam("SecretlyChoose")) { if (sa.hasParam("Reveal") && !sa.hasParam("SecretlyChoose")) {
game.getAction().reveal(chosen, p, dontRevealToOwner, sa.hasParam("RevealTitle") ? game.getAction().reveal(chosen, p, dontRevealToOwner, revealTitle ? sa.getParam("RevealTitle") :
sa.getParam("RevealTitle") : Localizer.getInstance().getMessage("lblChosenCards") + " "); Localizer.getInstance().getMessage("lblChosenCards") + " ", !revealTitle);
} }
} }
if (sa.hasParam("Reveal") && sa.hasParam("SecretlyChoose")) { if (sa.hasParam("Reveal") && sa.hasParam("SecretlyChoose")) {
for (final Player p : tgtPlayers) { for (final Player p : tgtPlayers) {
game.getAction().reveal(chosen, p, true, sa.hasParam("RevealTitle") ? game.getAction().reveal(chosen, p, true, revealTitle ?
sa.getParam("RevealTitle") : Localizer.getInstance().getMessage("lblChosenCards") + " "); sa.getParam("RevealTitle") : Localizer.getInstance().getMessage("lblChosenCards") + " ",
!revealTitle);
} }
} }
host.setChosenCards(chosen); host.setChosenCards(chosen);

View File

@@ -88,7 +88,6 @@ public class ClashEffect extends SpellAbilityEffect {
} }
final StringBuilder reveal = new StringBuilder(); final StringBuilder reveal = new StringBuilder();
reveal.append("OVERRIDE "); //will return substring with the original message parsed here..
Card pCard = null; Card pCard = null;
Card oCard = null; Card oCard = null;
final CardCollection toReveal = new CardCollection(); final CardCollection toReveal = new CardCollection();
@@ -122,7 +121,7 @@ public class ClashEffect extends SpellAbilityEffect {
reveal.append(winner + " " + Localizer.getInstance().getMessage("lblWinsClash") + "."); reveal.append(winner + " " + Localizer.getInstance().getMessage("lblWinsClash") + ".");
} }
player.getGame().getAction().revealTo(toReveal, player.getGame().getPlayers(), reveal.toString()); player.getGame().getAction().revealTo(toReveal, player.getGame().getPlayers(), reveal.toString(), false);
clashMoveToTopOrBottom(player, pCard, sa); clashMoveToTopOrBottom(player, pCard, sa);
clashMoveToTopOrBottom(opponent, oCard, sa); clashMoveToTopOrBottom(opponent, oCard, sa);

View File

@@ -1,7 +1,5 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import java.util.Map;
import forge.game.Game; import forge.game.Game;
import forge.game.GameLogEntryType; import forge.game.GameLogEntryType;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
@@ -18,6 +16,8 @@ import forge.util.Lang;
import forge.util.Localizer; import forge.util.Localizer;
import forge.util.TextUtil; import forge.util.TextUtil;
import java.util.Map;
public class MillEffect extends SpellAbilityEffect { public class MillEffect extends SpellAbilityEffect {
@Override @Override
public void resolve(SpellAbility sa) { public void resolve(SpellAbility sa) {
@@ -47,6 +47,8 @@ public class MillEffect extends SpellAbilityEffect {
continue; continue;
} }
String toZoneStr = destination.equals(ZoneType.Graveyard) ? "" : " (" +
Localizer.getInstance().getMessage("lblMilledToZone", destination.getTranslatedName()) + ")";
if (sa.hasParam("Optional")) { if (sa.hasParam("Optional")) {
String d = destination.equals(ZoneType.Graveyard) ? "" : " (" + destination.getTranslatedName() + ")"; String d = destination.equals(ZoneType.Graveyard) ? "" : " (" + destination.getTranslatedName() + ")";
final String prompt = TextUtil.concatWithSpace(Localizer.getInstance(). final String prompt = TextUtil.concatWithSpace(Localizer.getInstance().
@@ -61,11 +63,12 @@ public class MillEffect extends SpellAbilityEffect {
// graveyard to figure out which ones were milled. // graveyard to figure out which ones were milled.
if (!facedown && reveal) { // do not reveal when exiling face down if (!facedown && reveal) { // do not reveal when exiling face down
if (showRevealDialog) { if (showRevealDialog) {
game.getAction().reveal(milled, p, false); final String message = Localizer.getInstance().getMessage("lblMilledCards");
final boolean addSuffix = !toZoneStr.equals("");
game.getAction().reveal(milled, destination, p, false, message, addSuffix);
} }
StringBuilder sb = new StringBuilder(); p.getGame().getGameLog().add(GameLogEntryType.ZONE_CHANGE, p + " milled " +
sb.append(p).append(" milled ").append(milled).append(" to ").append(destination); Lang.joinHomogenous(milled) + toZoneStr + ".");
p.getGame().getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString());
} }
if (destination.equals(ZoneType.Exile)) { if (destination.equals(ZoneType.Exile)) {
for (final Card c : milled) { for (final Card c : milled) {

View File

@@ -0,0 +1,43 @@
package forge.game.ability.effects;
import com.google.common.collect.Maps;
import forge.game.Game;
import forge.game.GameEntityCounterTable;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CounterEnumType;
import forge.game.event.GameEventPlayerRadiation;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import java.util.Map;
public class RadiationEffect extends SpellAbilityEffect {
@Override
public void resolve(SpellAbility sa) {
final Card host = sa.getHostCard();
final Game game = host.getGame();
final int toAdd = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Add", "0"), sa);
final int toRem = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Remove", "0"), sa);
final Map<Player, Integer> list = Maps.newHashMap();
GameEntityCounterTable table = new GameEntityCounterTable();
for (final Player p : getTargetPlayers(sa)) {
if (!p.isInGame()) continue;
list.put(p, p.getCounters(CounterEnumType.RAD));
if (toAdd >= 1) p.addRadCounters(toAdd, host, table);
else if (toRem >= 1) p.removeRadCounters(toRem, host);
}
table.replaceCounterEffect(game, sa, true);
for (final Player p : list.keySet()) {
int oldCount = list.get(p);
int newCount = p.getCounters(CounterEnumType.RAD);
if (newCount > 0 && !p.hasRadiationEffect()) p.createRadiationEffect(host.getSetCode());
if (oldCount < newCount) game.fireEvent(new GameEventPlayerRadiation(p, host, newCount - oldCount));
}
}
}

View File

@@ -76,7 +76,9 @@ public class RevealEffect extends SpellAbilityEffect {
} }
if (sa.hasParam("RevealToAll") || sa.hasParam("Random")) { if (sa.hasParam("RevealToAll") || sa.hasParam("Random")) {
game.getAction().reveal(revealed, p, false, sa.getParamOrDefault("RevealTitle", "")); boolean revealTitle = sa.hasParam("RevealTitle");
game.getAction().reveal(revealed, p, false,
revealTitle ? sa.getParam("RevealTitle") : "", !revealTitle);
} else { } else {
game.getAction().reveal(revealed, p); game.getAction().reveal(revealed, p);
} }

View File

@@ -427,6 +427,8 @@ public enum CounterEnumType {
POISON("POISN"), POISON("POISN"),
RAD("RAD"),
TICKET("TICKET"), TICKET("TICKET"),
// Keyword Counters // Keyword Counters

View File

@@ -0,0 +1,21 @@
package forge.game.event;
import forge.game.card.Card;
import forge.game.player.Player;
public class GameEventPlayerRadiation extends GameEvent {
public final Player receiver;
public final Card source;
public final int change;
public GameEventPlayerRadiation(Player recv, Card src, int chng) {
receiver = recv;
source = src;
change = chng;
}
@Override
public <T> T visit(IGameEventVisitor<T> visitor) {
return visitor.visit(this);
}
}

View File

@@ -36,6 +36,7 @@ public interface IGameEventVisitor<T> {
T visit(GameEventPlayerDamaged gameEventPlayerDamaged); T visit(GameEventPlayerDamaged gameEventPlayerDamaged);
T visit(GameEventPlayerCounters event); T visit(GameEventPlayerCounters event);
T visit(GameEventPlayerPoisoned event); T visit(GameEventPlayerPoisoned event);
T visit(GameEventPlayerRadiation event);
T visit(GameEventPlayerPriority event); T visit(GameEventPlayerPriority event);
T visit(GameEventPlayerShardsChanged event); T visit(GameEventPlayerShardsChanged event);
T visit(GameEventPlayerStatsChanged event); T visit(GameEventPlayerStatsChanged event);
@@ -90,6 +91,7 @@ public interface IGameEventVisitor<T> {
public T visit(GameEventPlayerControl event) { return null; } public T visit(GameEventPlayerControl event) { return null; }
public T visit(GameEventPlayerCounters event) { return null; } public T visit(GameEventPlayerCounters event) { return null; }
public T visit(GameEventPlayerPoisoned event) { return null; } public T visit(GameEventPlayerPoisoned event) { return null; }
public T visit(GameEventPlayerRadiation event) { return null; }
public T visit(GameEventPlayerPriority event) { return null; } public T visit(GameEventPlayerPriority event) { return null; }
public T visit(GameEventPlayerShardsChanged event) { return null; } public T visit(GameEventPlayerShardsChanged event) { return null; }
public T visit(GameEventPlayerStatsChanged event) { return null; } public T visit(GameEventPlayerStatsChanged event) { return null; }

View File

@@ -17,43 +17,22 @@
*/ */
package forge.game.phase; package forge.game.phase;
import java.util.*; import com.google.common.base.Predicates;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.*; import com.google.common.collect.Lists;
import org.apache.commons.lang3.time.StopWatch; import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import forge.game.Game; import forge.game.*;
import forge.game.GameEntity;
import forge.game.GameEntityCounterTable;
import forge.game.GameStage;
import forge.game.GameType;
import forge.game.GlobalRuleChange;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.effects.AddTurnEffect; import forge.game.ability.effects.AddTurnEffect;
import forge.game.ability.effects.SkipPhaseEffect; import forge.game.ability.effects.SkipPhaseEffect;
import forge.game.card.Card; import forge.game.card.*;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardUtil;
import forge.game.card.CardPredicates.Presets; import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardZoneTable;
import forge.game.card.CounterEnumType;
import forge.game.combat.Combat; import forge.game.combat.Combat;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.cost.CostEnlist; import forge.game.cost.CostEnlist;
import forge.game.cost.CostExert; import forge.game.cost.CostExert;
import forge.game.event.GameEventAttackersDeclared; import forge.game.event.*;
import forge.game.event.GameEventBlockersDeclared;
import forge.game.event.GameEventCardStatsChanged;
import forge.game.event.GameEventCombatChanged;
import forge.game.event.GameEventCombatEnded;
import forge.game.event.GameEventGameRestarted;
import forge.game.event.GameEventPlayerPriority;
import forge.game.event.GameEventPlayerStatsChanged;
import forge.game.event.GameEventTokenStateUpdate;
import forge.game.event.GameEventTurnBegan;
import forge.game.event.GameEventTurnEnded;
import forge.game.event.GameEventTurnPhase;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType; import forge.game.replacement.ReplacementType;
@@ -64,9 +43,14 @@ import forge.game.trigger.TriggerType;
import forge.game.zone.Zone; import forge.game.zone.Zone;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.CollectionSuppliers; import forge.util.CollectionSuppliers;
import forge.util.Lang;
import forge.util.Localizer;
import forge.util.TextUtil; import forge.util.TextUtil;
import forge.util.maps.HashMapOfLists; import forge.util.maps.HashMapOfLists;
import forge.util.maps.MapOfLists; import forge.util.maps.MapOfLists;
import org.apache.commons.lang3.time.StopWatch;
import java.util.*;
/** /**
@@ -299,6 +283,9 @@ public class PhaseHandler implements java.io.Serializable {
if (playerTurn.isArchenemy()) { if (playerTurn.isArchenemy()) {
playerTurn.setSchemeInMotion(); playerTurn.setSchemeInMotion();
} }
if (playerTurn.hasRadiationEffect()) {
handleRadiation();
}
GameEntityCounterTable table = new GameEntityCounterTable(); GameEntityCounterTable table = new GameEntityCounterTable();
// all Saga get Lore counter at the begin of pre combat // all Saga get Lore counter at the begin of pre combat
for (Card c : playerTurn.getCardsIn(ZoneType.Battlefield)) { for (Card c : playerTurn.getCardsIn(ZoneType.Battlefield)) {
@@ -541,6 +528,36 @@ public class PhaseHandler implements java.io.Serializable {
} }
} }
private void handleRadiation() {
int numRad = playerTurn.getCounters(CounterEnumType.RAD);
if (numRad == 0) playerTurn.removeRadiationEffect();
else {
final CardZoneTable table = new CardZoneTable();
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
moveParams.put(AbilityKey.LastStateBattlefield, game.getLastStateBattlefield());
moveParams.put(AbilityKey.LastStateGraveyard, game.getLastStateGraveyard());
final SpellAbility sa = new SpellAbility.EmptySa(playerTurn.getRadiationEffect(), playerTurn);
final CardCollectionView milled = playerTurn.mill(numRad, ZoneType.Graveyard, sa,
table, moveParams);
game.getAction().reveal(milled, playerTurn, false,
Localizer.getInstance().getMessage("lblMilledCards", playerTurn), false);
game.getGameLog().add(GameLogEntryType.ZONE_CHANGE, playerTurn + " milled " +
Lang.joinHomogenous(milled) + ".");
table.triggerChangesZoneAll(game, sa);
int n = CardLists.filter(milled, Predicates.not(CardPredicates.Presets.LANDS)).size();
final Map<Player, Integer> lossMap = Maps.newHashMap();
final int lost = playerTurn.loseLife(n, false, false);
if (lost > 0) {
lossMap.put(playerTurn, lost);
}
if (!lossMap.isEmpty()) { // Run triggers if any player actually lost life
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPIMap(lossMap);
game.getTriggerHandler().runTrigger(TriggerType.LifeLostAll, runParams, false);
}
playerTurn.removeRadCounters(n, playerTurn.getRadiationEffect());
}
}
private void declareAttackersTurnBasedAction() { private void declareAttackersTurnBasedAction() {
final Player whoDeclares = playerDeclaresAttackers == null || playerDeclaresAttackers.hasLost() final Player whoDeclares = playerDeclaresAttackers == null || playerDeclaresAttackers.hasLost()
? playerTurn ? playerTurn

View File

@@ -17,39 +17,9 @@
*/ */
package forge.game.player; package forge.game.player;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.Set;
import java.util.SortedSet;
import forge.game.event.*;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.LandAbility;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList; import com.google.common.collect.*;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.collect.Table;
import com.google.common.collect.TreeBasedTable;
import forge.ImageKeys; import forge.ImageKeys;
import forge.LobbyPlayer; import forge.LobbyPlayer;
import forge.card.CardStateName; import forge.card.CardStateName;
@@ -58,36 +28,17 @@ import forge.card.ColorSet;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard; import forge.card.mana.ManaCostShard;
import forge.game.CardTraitBase; import forge.game.*;
import forge.game.Game;
import forge.game.GameActionUtil;
import forge.game.GameEntity;
import forge.game.GameEntityCounterTable;
import forge.game.GameLogEntryType;
import forge.game.GameStage;
import forge.game.GameType;
import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.ability.effects.DetachedCardEffect; import forge.game.ability.effects.DetachedCardEffect;
import forge.game.card.Card; import forge.game.card.*;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets; import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil; import forge.game.event.*;
import forge.game.card.CardZoneTable; import forge.game.keyword.*;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.keyword.Companion;
import forge.game.keyword.Keyword;
import forge.game.keyword.KeywordCollection;
import forge.game.keyword.KeywordCollection.KeywordCollectionView; import forge.game.keyword.KeywordCollection.KeywordCollectionView;
import forge.game.keyword.KeywordInterface;
import forge.game.keyword.KeywordsChange;
import forge.game.mana.ManaPool; import forge.game.mana.ManaPool;
import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
@@ -95,16 +46,10 @@ import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementHandler; import forge.game.replacement.ReplacementHandler;
import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType; import forge.game.replacement.ReplacementType;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.LandAbility;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbility; import forge.game.staticability.*;
import forge.game.staticability.StaticAbilityCantBeCast;
import forge.game.staticability.StaticAbilityCantDiscard;
import forge.game.staticability.StaticAbilityCantBecomeMonarch;
import forge.game.staticability.StaticAbilityCantDraw;
import forge.game.staticability.StaticAbilityCantGainLosePayLife;
import forge.game.staticability.StaticAbilityCantPutCounter;
import forge.game.staticability.StaticAbilityCantTarget;
import forge.game.staticability.StaticAbilityCantSetSchemesInMotion;
import forge.game.trigger.Trigger; import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerHandler; import forge.game.trigger.TriggerHandler;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
@@ -114,13 +59,14 @@ import forge.game.zone.Zone;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.item.IPaperCard; import forge.item.IPaperCard;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.util.Aggregates; import forge.util.*;
import forge.util.Lang;
import forge.util.Localizer;
import forge.util.MyRandom;
import forge.util.TextUtil;
import forge.util.collect.FCollection; import forge.util.collect.FCollection;
import forge.util.collect.FCollectionView; import forge.util.collect.FCollectionView;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import java.util.*;
import java.util.Map.Entry;
/** /**
* <p> * <p>
@@ -240,6 +186,8 @@ public class Player extends GameEntity implements Comparable<Player> {
private Card monarchEffect; private Card monarchEffect;
private Card initiativeEffect; private Card initiativeEffect;
private Card blessingEffect; private Card blessingEffect;
private Card radiationEffect;
private Card keywordEffect; private Card keywordEffect;
private Map<Long, Integer> additionalVotes = Maps.newHashMap(); private Map<Long, Integer> additionalVotes = Maps.newHashMap();
@@ -986,6 +934,18 @@ public class Player extends GameEntity implements Comparable<Player> {
getGame().fireEvent(new GameEventPlayerCounters(this, null, 0, 0)); getGame().fireEvent(new GameEventPlayerCounters(this, null, 0, 0));
} }
public final void addRadCounters(final int num, final Card source, GameEntityCounterTable table) {
addCounter(CounterEnumType.RAD, num, source.getController(), table);
}
public final void removeRadCounters(final int num, final Card source) {
int oldRad = getCounters(CounterEnumType.RAD);
if (oldRad != 0) subtractCounter(CounterEnumType.RAD, num);
int newRad = getCounters(CounterEnumType.RAD);
if (newRad == 0) removeRadiationEffect();
if (oldRad != newRad) game.fireEvent(new GameEventPlayerRadiation(this, source, newRad - oldRad));
}
// TODO Merge These calls into the primary counter calls // TODO Merge These calls into the primary counter calls
public final int getPoisonCounters() { public final int getPoisonCounters() {
return getCounters(CounterEnumType.POISON); return getCounters(CounterEnumType.POISON);
@@ -3462,6 +3422,42 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
} }
public final Card getRadiationEffect() {
return radiationEffect;
}
public void createRadiationEffect(String setCode) {
final PlayerZone com = getZone(ZoneType.Command);
if (radiationEffect == null) {
radiationEffect = new Card(game.nextCardId(), null, game);
radiationEffect.setOwner(this);
radiationEffect.setImmutable(true);
radiationEffect.setImageKey("t:radiation");
radiationEffect.setName("Radiation");
radiationEffect.setSetCode(setCode);
String desc = "Mode$ Continuous | Affected$ Card.Self | Description$ At the beginning of your precombat " +
"main phase, if you have any rad counters, mill that many cards. For each nonland card milled " +
"this way, you lose 1 life and a rad counter.";
StaticAbility st = StaticAbility.create(desc, radiationEffect, radiationEffect.getCurrentState(), true);
radiationEffect.addStaticAbility(st);
radiationEffect.updateStateForView();
}
com.add(radiationEffect);
this.updateZoneForView(com);
}
public void removeRadiationEffect() {
final PlayerZone com = getZone(ZoneType.Command);
if (radiationEffect != null) {
com.remove(radiationEffect);
radiationEffect = null;
this.updateZoneForView(com);
}
}
public boolean hasRadiationEffect() {
return radiationEffect != null;
}
public void updateKeywordCardAbilityText() { public void updateKeywordCardAbilityText() {
if (getKeywordCard() == null) if (getKeywordCard() == null)
return; return;
@@ -3735,7 +3731,7 @@ public class Player extends GameEntity implements Comparable<Player> {
lki.setZone(c.getZone()); lki.setZone(c.getZone());
revealCards.add(lki); revealCards.add(lki);
} }
game.getAction().revealTo(revealCards, otherPlayers, Localizer.getInstance().getMessage("lblRevealFaceDownCards")); game.getAction().revealTo(revealCards, otherPlayers, Localizer.getInstance().getMessage("lblRevealFaceDownCards"), true);
} }
} }

View File

@@ -163,8 +163,14 @@ public abstract class PlayerController {
public final void reveal(CardCollectionView cards, ZoneType zone, Player owner) { public final void reveal(CardCollectionView cards, ZoneType zone, Player owner) {
reveal(cards, zone, owner, null); reveal(cards, zone, owner, null);
} }
public abstract void reveal(CardCollectionView cards, ZoneType zone, Player owner, String messagePrefix); public final void reveal(CardCollectionView cards, ZoneType zone, Player owner, String messagePrefix) {
public abstract void reveal(List<CardView> cards, ZoneType zone, PlayerView owner, String messagePrefix); reveal(cards, zone, owner, null, true);
}
public abstract void reveal(CardCollectionView cards, ZoneType zone, Player owner, String messagePrefix, boolean addMsgSuffix);
public final void reveal(List<CardView> cards, ZoneType zone, PlayerView owner, String messagePrefix) {
reveal(cards, zone, owner, null, true);
}
public abstract void reveal(List<CardView> cards, ZoneType zone, PlayerView owner, String messagePrefix, boolean addMsgSuffix);
/** Shows message to player to reveal chosen cardName, creatureType, number etc. AI must analyze API to understand what that is */ /** Shows message to player to reveal chosen cardName, creatureType, number etc. AI must analyze API to understand what that is */
public abstract void notifyOfValue(SpellAbility saSource, GameObject realtedTarget, String value); public abstract void notifyOfValue(SpellAbility saSource, GameObject realtedTarget, String value);

View File

@@ -57,6 +57,7 @@ public class TriggerMilledAll extends Trigger {
} }
sa.setTriggeringObject(AbilityKey.Cards, cards); sa.setTriggeringObject(AbilityKey.Cards, cards);
sa.setTriggeringObject(AbilityKey.Amount, cards.size());
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Player); sa.setTriggeringObjectsFrom(runParams, AbilityKey.Player);
} }

View File

@@ -80,6 +80,7 @@ public class VField implements IVDoc<CField> {
private final FLabel lblEnergy = new FLabel.Builder().fontAlign(SwingConstants.CENTER).fontStyle(Font.BOLD).icon(FSkin.getImage(FSkinProp.IMG_ENERGY)).iconInBackground().build(); private final FLabel lblEnergy = new FLabel.Builder().fontAlign(SwingConstants.CENTER).fontStyle(Font.BOLD).icon(FSkin.getImage(FSkinProp.IMG_ENERGY)).iconInBackground().build();
private final FLabel lblExperience = new FLabel.Builder().fontAlign(SwingConstants.CENTER).fontStyle(Font.BOLD).icon(FSkin.getImage(FSkinProp.IMG_EXPERIENCE)).iconInBackground().build(); private final FLabel lblExperience = new FLabel.Builder().fontAlign(SwingConstants.CENTER).fontStyle(Font.BOLD).icon(FSkin.getImage(FSkinProp.IMG_EXPERIENCE)).iconInBackground().build();
private final FLabel lblTicket = new FLabel.Builder().fontAlign(SwingConstants.CENTER).fontStyle(Font.BOLD).icon(FSkin.getImage(FSkinProp.IMG_TICKET)).iconInBackground().build(); private final FLabel lblTicket = new FLabel.Builder().fontAlign(SwingConstants.CENTER).fontStyle(Font.BOLD).icon(FSkin.getImage(FSkinProp.IMG_TICKET)).iconInBackground().build();
private final FLabel lblRad = new FLabel.Builder().fontAlign(SwingConstants.CENTER).fontStyle(Font.BOLD).icon(FSkin.getImage(FSkinProp.IMG_RAD)).iconInBackground().build();
private final PhaseIndicator phaseIndicator = new PhaseIndicator(); private final PhaseIndicator phaseIndicator = new PhaseIndicator();
@@ -115,6 +116,7 @@ public class VField implements IVDoc<CField> {
lblEnergy.setFocusable(false); lblEnergy.setFocusable(false);
lblExperience.setFocusable(false); lblExperience.setFocusable(false);
lblTicket.setFocusable(false); lblTicket.setFocusable(false);
lblRad.setFocusable(false);
avatarArea.setOpaque(false); avatarArea.setOpaque(false);
avatarArea.setBackground(FSkin.getColor(FSkin.Colors.CLR_HOVER)); avatarArea.setBackground(FSkin.getColor(FSkin.Colors.CLR_HOVER));
@@ -236,6 +238,24 @@ public class VField implements IVDoc<CField> {
avatarArea.add(lblLife, "w 100%!, h 20px!, wrap"); avatarArea.add(lblLife, "w 100%!, h 20px!, wrap");
} }
private void addLblRad() {
if (lblRad.isShowing() || lblExperience.isShowing() || lblEnergy.isShowing() || lblPoison.isShowing()) {
return;
}
avatarArea.remove(lblLife);
lblLife.setIcon(FSkin.getImage(FSkinProp.ICO_QUEST_LIFE));
avatarArea.add(lblLife, "w 50%!, h 20px!, split 2");
avatarArea.add(lblRad, "w 50%!, h 20px!, wrap");
}
private void removeLblRad() {
if (!lblRad.isShowing()) {
return;
}
avatarArea.remove(lblRad);
avatarArea.remove(lblLife);
avatarArea.add(lblLife, "w 100%!, h 20px!, wrap");
}
private void addLblExperience() { private void addLblExperience() {
if (lblExperience.isShowing() || lblEnergy.isShowing() || lblPoison.isShowing()) { if (lblExperience.isShowing() || lblEnergy.isShowing() || lblPoison.isShowing()) {
@@ -307,11 +327,13 @@ public class VField implements IVDoc<CField> {
final int poison = player.getCounters(CounterEnumType.POISON); final int poison = player.getCounters(CounterEnumType.POISON);
final int energy = player.getCounters(CounterEnumType.ENERGY); final int energy = player.getCounters(CounterEnumType.ENERGY);
final int experience = player.getCounters(CounterEnumType.EXPERIENCE); final int experience = player.getCounters(CounterEnumType.EXPERIENCE);
final int rad = player.getCounters(CounterEnumType.RAD);
final int ticket = player.getCounters(CounterEnumType.TICKET); final int ticket = player.getCounters(CounterEnumType.TICKET);
if (poison > 0) { if (poison > 0) {
removeLblEnergy(); removeLblEnergy();
removeLblExperience(); removeLblExperience();
removeLblRad();
removeLblTicket(); removeLblTicket();
addLblPoison(); addLblPoison();
lblPoison.setText(String.valueOf(poison)); lblPoison.setText(String.valueOf(poison));
@@ -326,6 +348,7 @@ public class VField implements IVDoc<CField> {
if (energy > 0) { if (energy > 0) {
removeLblExperience(); removeLblExperience();
removeLblRad();
removeLblTicket(); removeLblTicket();
if (poison == 0) { if (poison == 0) {
addLblEnergy(); addLblEnergy();
@@ -336,6 +359,7 @@ public class VField implements IVDoc<CField> {
} }
if (experience > 0) { if (experience > 0) {
removeLblRad();
removeLblTicket(); removeLblTicket();
if (poison == 0 && energy == 0) { if (poison == 0 && energy == 0) {
addLblExperience(); addLblExperience();
@@ -345,8 +369,18 @@ public class VField implements IVDoc<CField> {
removeLblExperience(); removeLblExperience();
} }
if (ticket > 0) { if (rad > 0) {
removeLblTicket();
if (poison == 0 && energy == 0 && experience == 0) { if (poison == 0 && energy == 0 && experience == 0) {
addLblRad();
lblRad.setText(String.valueOf(rad));
}
} else {
removeLblRad();
}
if (ticket > 0) {
if (poison == 0 && energy == 0 && experience == 0 && rad == 0) {
addLblTicket(); addLblTicket();
lblTicket.setText(String.valueOf(ticket)); lblTicket.setText(String.valueOf(ticket));
} }

View File

@@ -239,12 +239,12 @@ public class PlayerControllerForTests extends PlayerController {
} }
@Override @Override
public void reveal(CardCollectionView cards, ZoneType zone, Player owner, String messagePrefix) { public void reveal(CardCollectionView cards, ZoneType zone, Player owner, String messagePrefix, boolean addSuffix) {
//nothing needs to be done here //nothing needs to be done here
} }
@Override @Override
public void reveal(List<CardView> cards, ZoneType zone, PlayerView owner, String messagePrefix) { public void reveal(List<CardView> cards, ZoneType zone, PlayerView owner, String messagePrefix, boolean addSuffix) {
//nothing needs to be done here //nothing needs to be done here
} }

View File

@@ -146,6 +146,7 @@ public enum FSkinImage implements FImage {
COUNTERS_MULTI (FSkinProp.IMG_COUNTERS_MULTI, SourceFile.ICONS), COUNTERS_MULTI (FSkinProp.IMG_COUNTERS_MULTI, SourceFile.ICONS),
ENERGY (FSkinProp.IMG_ENERGY, SourceFile.ICONS), ENERGY (FSkinProp.IMG_ENERGY, SourceFile.ICONS),
TICKET (FSkinProp.IMG_TICKET, SourceFile.ICONS), TICKET (FSkinProp.IMG_TICKET, SourceFile.ICONS),
RAD (FSkinProp.IMG_RAD, SourceFile.ICONS),
//Dock Icons //Dock Icons
SHORTCUTS (FSkinProp.ICO_SHORTCUTS, SourceFile.ICONS), SHORTCUTS (FSkinProp.ICO_SHORTCUTS, SourceFile.ICONS),

View File

@@ -472,6 +472,7 @@ public class VPlayerPanel extends FContainer {
private int energyCounters = player.getCounters(CounterEnumType.ENERGY); private int energyCounters = player.getCounters(CounterEnumType.ENERGY);
private int experienceCounters = player.getCounters(CounterEnumType.EXPERIENCE); private int experienceCounters = player.getCounters(CounterEnumType.EXPERIENCE);
private int ticketCounters = player.getCounters(CounterEnumType.TICKET); private int ticketCounters = player.getCounters(CounterEnumType.TICKET);
private int radCounters = player.getCounters(CounterEnumType.RAD);
private int manaShards = player.getNumManaShards(); private int manaShards = player.getNumManaShards();
private String lifeStr = String.valueOf(life); private String lifeStr = String.valueOf(life);
@@ -525,7 +526,7 @@ public class VPlayerPanel extends FContainer {
adjustHeight = 1; adjustHeight = 1;
float divider = Gdx.app.getGraphics().getHeight() > 900 ? 1.2f : 2f; float divider = Gdx.app.getGraphics().getHeight() > 900 ? 1.2f : 2f;
if(Forge.altPlayerLayout && !Forge.altZoneTabs && Forge.isLandscapeMode()) { if(Forge.altPlayerLayout && !Forge.altZoneTabs && Forge.isLandscapeMode()) {
if (poisonCounters == 0 && energyCounters == 0 && experienceCounters == 0 && ticketCounters ==0 && manaShards == 0) { if (poisonCounters == 0 && energyCounters == 0 && experienceCounters == 0 && ticketCounters == 0 && radCounters == 0 && manaShards == 0) {
g.fillRect(Color.DARK_GRAY, 0, 0, INFO2_FONT.getBounds(lifeStr).width+1, INFO2_FONT.getBounds(lifeStr).height+1); g.fillRect(Color.DARK_GRAY, 0, 0, INFO2_FONT.getBounds(lifeStr).width+1, INFO2_FONT.getBounds(lifeStr).height+1);
g.drawText(lifeStr, INFO2_FONT, getInfoForeColor().getColor(), 0, 0, getWidth(), getHeight(), false, Align.left, false); g.drawText(lifeStr, INFO2_FONT, getInfoForeColor().getColor(), 0, 0, getWidth(), getHeight(), false, Align.left, false);
} else { } else {
@@ -554,6 +555,12 @@ public class VPlayerPanel extends FContainer {
g.drawText(String.valueOf(experienceCounters), INFO_FONT, getInfoForeColor().getColor(), textStart, (halfHeight*mod)+2, textWidth, halfHeight, false, Align.left, false); g.drawText(String.valueOf(experienceCounters), INFO_FONT, getInfoForeColor().getColor(), textStart, (halfHeight*mod)+2, textWidth, halfHeight, false, Align.left, false);
mod+=1; mod+=1;
} }
if (radCounters > 0) {
g.fillRect(Color.DARK_GRAY, 0, (halfHeight*mod)+2, INFO_FONT.getBounds(String.valueOf(radCounters)).width+halfHeight+1, INFO_FONT.getBounds(String.valueOf(radCounters)).height+1);
g.drawImage(FSkinImage.RAD, 0, (halfHeight*mod)+2, halfHeight, halfHeight);
g.drawText(String.valueOf(radCounters), INFO_FONT, getInfoForeColor().getColor(), textStart, (halfHeight*mod)+2, textWidth, halfHeight, false, Align.left, false);
mod+=1;
}
if (ticketCounters > 0) { if (ticketCounters > 0) {
g.fillRect(Color.DARK_GRAY, 0, (halfHeight*mod)+2, INFO_FONT.getBounds(String.valueOf(ticketCounters)).width+halfHeight+1, INFO_FONT.getBounds(String.valueOf(ticketCounters)).height+1); g.fillRect(Color.DARK_GRAY, 0, (halfHeight*mod)+2, INFO_FONT.getBounds(String.valueOf(ticketCounters)).width+halfHeight+1, INFO_FONT.getBounds(String.valueOf(ticketCounters)).height+1);
g.drawImage(FSkinImage.TICKET, 0, (halfHeight*mod)+2, halfHeight, halfHeight); g.drawImage(FSkinImage.TICKET, 0, (halfHeight*mod)+2, halfHeight, halfHeight);

View File

@@ -1,7 +1,7 @@
Name:Death Ring Name:Death Ring
Types:Artifact Types:Artifact
A:AB$ RepeatEach | Cost$ PayShards<2> | ActivationZone$ Command | SorcerySpeed$ True | IsPresent$ Creature.YouCtrl | RepeatPlayers$ Player | RepeatSubAbility$ DBChooseRandom | SubAbility$ DBPutCounter | SpellDescription$ For each player, put a -1/-1 counter on a random creature with the lowest toughness that player controls. Then if your creature has power less than one, sacrifice it. A:AB$ RepeatEach | Cost$ PayShards<2> | ActivationZone$ Command | SorcerySpeed$ True | IsPresent$ Creature.YouCtrl | RepeatPlayers$ Player | RepeatSubAbility$ DBChooseRandom | SubAbility$ DBPutCounter | SpellDescription$ For each player, put a -1/-1 counter on a random creature with the lowest toughness that player controls. Then if your creature has power less than one, sacrifice it.
SVar:DBChooseRandom:DB$ ChooseCard | AtRandom$ True | Choices$ Creature.leastToughnessControlledByRememberedPlayer | RevealTitle$ OVERRIDE Randomly chosen creature: | Reveal$ True | RememberChosen$ True SVar:DBChooseRandom:DB$ ChooseCard | AtRandom$ True | Choices$ Creature.leastToughnessControlledByRememberedPlayer | RevealTitle$ Randomly chosen creature: | Reveal$ True | RememberChosen$ True
SVar:DBPutCounter:DB$ PutCounter | Defined$ Remembered | CounterType$ M1M1 | SubAbility$ ConditionalSac | StackDescription$ None | SpellDescription$ Activate only if you control a creature and only as a sorcery. SVar:DBPutCounter:DB$ PutCounter | Defined$ Remembered | CounterType$ M1M1 | SubAbility$ ConditionalSac | StackDescription$ None | SpellDescription$ Activate only if you control a creature and only as a sorcery.
SVar:ConditionalSac:DB$ SacrificeAll | Defined$ Remembered.powerLT1+YouCtrl | SubAbility$ DBCleanup | SpellDescription$ If your creature has power less than one, sacrifice it. SVar:ConditionalSac:DB$ SacrificeAll | Defined$ Remembered.powerLT1+YouCtrl | SubAbility$ DBCleanup | SpellDescription$ If your creature has power less than one, sacrifice it.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True

View File

@@ -1,6 +1,6 @@
Name:Call to the Void Name:Call to the Void
ManaCost:4 B ManaCost:4 B
Types:Sorcery Types:Sorcery
A:SP$ ChooseCard | Defined$ Player | Choices$ Creature | SecretlyChoose$ True | Amount$ 1 | ControlAndNot$ True | ChoiceTitle$ Secretly choose a creature | Reveal$ True | RevealTitle$ OVERRIDE Chosen creatures. They will be destroyed. | SubAbility$ DBDestroyChosen | Mandatory$ True A:SP$ ChooseCard | Defined$ Player | Choices$ Creature | SecretlyChoose$ True | Amount$ 1 | ControlAndNot$ True | ChoiceTitle$ Secretly choose a creature | Reveal$ True | RevealTitle$ Chosen creatures. They will be destroyed. | SubAbility$ DBDestroyChosen | Mandatory$ True
SVar:DBDestroyChosen:DB$ DestroyAll | ValidCards$ Creature.ChosenCard SVar:DBDestroyChosen:DB$ DestroyAll | ValidCards$ Creature.ChosenCard
Oracle:Each player secretly chooses a creature they control and a creature they don't control. Then those choices are revealed. Destroy each creature chosen this way. Oracle:Each player secretly chooses a creature they control and a creature they don't control. Then those choices are revealed. Destroy each creature chosen this way.

View File

@@ -5,7 +5,7 @@ PT:6/4
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ At the beginning of your upkeep, choose target nonland permanent you control and up to two target nonland permanents you don't control. Destroy one of them at random. T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ At the beginning of your upkeep, choose target nonland permanent you control and up to two target nonland permanents you don't control. Destroy one of them at random.
SVar:TrigPump:DB$ Pump | ValidTgts$ Permanent.nonLand+YouCtrl | TgtPrompt$ Select target nonland permanent you control | Mandatory$ True | IsCurse$ True | SubAbility$ DBPump SVar:TrigPump:DB$ Pump | ValidTgts$ Permanent.nonLand+YouCtrl | TgtPrompt$ Select target nonland permanent you control | Mandatory$ True | IsCurse$ True | SubAbility$ DBPump
SVar:DBPump:DB$ Pump | ValidTgts$ Permanent.nonLand+YouDontCtrl | TgtPrompt$ Select up to two target nonland permanents you don't control | TargetMin$ 0 | TargetMax$ 2 | IsCurse$ True | SubAbility$ DBChooseRandom SVar:DBPump:DB$ Pump | ValidTgts$ Permanent.nonLand+YouDontCtrl | TgtPrompt$ Select up to two target nonland permanents you don't control | TargetMin$ 0 | TargetMax$ 2 | IsCurse$ True | SubAbility$ DBChooseRandom
SVar:DBChooseRandom:DB$ ChooseCard | AtRandom$ True | Reveal$ True | RevealTitle$ OVERRIDE Randomly chosen permanent: | DefinedCards$ TargetedCard | SubAbility$ DBDestroy SVar:DBChooseRandom:DB$ ChooseCard | AtRandom$ True | Reveal$ True | RevealTitle$ Randomly chosen permanent: | DefinedCards$ TargetedCard | SubAbility$ DBDestroy
SVar:DBDestroy:DB$ Destroy | Defined$ ChosenCard | SubAbility$ DBCleanup SVar:DBDestroy:DB$ Destroy | Defined$ ChosenCard | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True
Oracle:At the beginning of your upkeep, choose target nonland permanent you control and up to two target nonland permanents you don't control. Destroy one of them at random. Oracle:At the beginning of your upkeep, choose target nonland permanent you control and up to two target nonland permanents you don't control. Destroy one of them at random.

View File

@@ -14,7 +14,7 @@ SVar:TrigRepeatEach:DB$ RepeatEach | UseImprinted$ True | RepeatCards$ Card.Note
SVar:DBCopyRandom:DB$ NameCard | Defined$ You | AtRandom$ True | ValidCards$ Card.ManaCost=Imprinted | SubAbility$ DBMake SVar:DBCopyRandom:DB$ NameCard | Defined$ You | AtRandom$ True | ValidCards$ Card.ManaCost=Imprinted | SubAbility$ DBMake
SVar:DBMake:DB$ MakeCard | Name$ ChosenName | Zone$ None | RememberMade$ True | SubAbility$ DBClearNamed SVar:DBMake:DB$ MakeCard | Name$ ChosenName | Zone$ None | RememberMade$ True | SubAbility$ DBClearNamed
SVar:DBClearNamed:DB$ Cleanup | ClearNamedCard$ True SVar:DBClearNamed:DB$ Cleanup | ClearNamedCard$ True
SVar:DBReveal:DB$ Reveal | Defined$ You | RevealDefined$ Remembered | RevealToAll$ True | RevealTitle$ OVERRIDE Cards created by Maelstrom Archangel Avatar | SubAbility$ DBChoose SVar:DBReveal:DB$ Reveal | Defined$ You | RevealDefined$ Remembered | RevealToAll$ True | RevealTitle$ Cards created by Maelstrom Archangel Avatar | SubAbility$ DBChoose
SVar:DBChoose:DB$ ChooseCard | UnlessCost$ 3 | UnlessPayer$ You | UnlessSwitched$ True | Choices$ Card.IsRemembered | ChoiceZone$ None | SubAbility$ DBCopyPerm | SpellDescription$ You may pay {3}. If you do, choose one of those copies. If a copy of a permanent card is chosen, you may create a token that's a copy of that card. If a copy of an instant or sorcery card is chosen, you may cast the copy without paying its mana cost. SVar:DBChoose:DB$ ChooseCard | UnlessCost$ 3 | UnlessPayer$ You | UnlessSwitched$ True | Choices$ Card.IsRemembered | ChoiceZone$ None | SubAbility$ DBCopyPerm | SpellDescription$ You may pay {3}. If you do, choose one of those copies. If a copy of a permanent card is chosen, you may create a token that's a copy of that card. If a copy of an instant or sorcery card is chosen, you may cast the copy without paying its mana cost.
SVar:DBCopyPerm:DB$ CopyPermanent | Optional$ True | Defined$ ChosenCard | ConditionDefined$ ChosenCard | ConditionPresent$ Permanent | ConditionCompare$ GE1 | SubAbility$ DBCastSp SVar:DBCopyPerm:DB$ CopyPermanent | Optional$ True | Defined$ ChosenCard | ConditionDefined$ ChosenCard | ConditionPresent$ Permanent | ConditionCompare$ GE1 | SubAbility$ DBCastSp
SVar:DBCastSp:DB$ Play | Defined$ ChosenCard | ZoneRegardless$ True | Optional$ True | WithoutManaCost$ True | ValidSA$ Spell | ConditionDefined$ ChosenCard | ConditionPresent$ Permanent | ConditionCompare$ EQ0 | SubAbility$ DBCleanup SVar:DBCastSp:DB$ Play | Defined$ ChosenCard | ZoneRegardless$ True | Optional$ True | WithoutManaCost$ True | ValidSA$ Spell | ConditionDefined$ ChosenCard | ConditionPresent$ Permanent | ConditionCompare$ EQ0 | SubAbility$ DBCleanup

View File

@@ -0,0 +1,12 @@
Name:Feral Ghoul
ManaCost:2 B
Types:Creature Zombie Mutant
PT:2/2
K:Menace
T:Mode$ ChangesZone | ValidCard$ Creature.Other+YouCtrl | Origin$ Battlefield | Destination$ Graveyard | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever another creature you control dies, put a +1/+1 counter on CARDNAME.
SVar:TrigPutCounter:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ 1
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigRadiation | TriggerDescription$ When CARDNAME dies, each opponent gets a number of rad counters equal to its power.
SVar:TrigRadiation:DB$ Radiation | Defined$ Opponent | Add$ TriggeredCard$CardPower
DeckHas:Ability$Counters
DeckHints:Ability$Sacrifice
Oracle:Menace\nWhenever another creature you control dies, put a +1/+1 counter on Feral Ghoul.\nWhen Feral Ghoul dies, each opponent gets a number of rad counters equal to its power.

View File

@@ -0,0 +1,13 @@
Name:The Wise Mothman
ManaCost:1 B G U
Types:Legendary Creature Insect Mutant
PT:3/3
K:Flying
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigRadiation | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, each player gets a rad counter.
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigRadiation | TriggerZones$ Battlefield | Secondary$ True | TriggerDescription$ Whenever CARDNAME enters the battlefield attacks, each player gets a rad counter.
SVar:TrigRadiation:DB$ Radiation | Defined$ Player | Add$ 1
T:Mode$ MilledAll | ValidPlayer$ Player | ValidCard$ Card.nonLand | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever one or more nonland cards are milled, put a +1/+1 counter on each of up to X target creatures, where X is the number of nonland cards milled this way.
SVar:TrigPutCounter:DB$ PutCounter | CounterNum$ 1 | CounterType$ P1P1 | TargetMin$ 0 | TargetMax$ TriggerCount$Amount | ValidTgts$ Creature | TgtPrompt$ Select up to X target creatures
DeckHints:Ability$Mill
DeckHas:Ability$Counters|Mill
Oracle:Flying\nWhenever The Wise Mothman enters the battlefield or attacks, each player gets a rad counter.\nWhenever one or more nonland cards are milled, put a +1/+1 counter on each of up to X target creatures, where X is the number of nonland cards milled this way.

View File

@@ -1507,6 +1507,8 @@ lblCombat=Kampf
lblNonCombat=Nicht-Kampf lblNonCombat=Nicht-Kampf
lblLogSourceDealsNDamageOfTypeToDest={0} verursacht {1} {2} Schaden bei {3}{4}. lblLogSourceDealsNDamageOfTypeToDest={0} verursacht {1} {2} Schaden bei {3}{4}.
lblLogPlayerReceivesNPosionCounterFrom={0} hat {1} Giftmarken von {2} erhalten. lblLogPlayerReceivesNPosionCounterFrom={0} hat {1} Giftmarken von {2} erhalten.
lblLogPlayerRadiation={0} erhält {1} von {2}.
lblLogPlayerRadRemove={0} entfernt {1} aufgrund von {2}.
lblLogPlayerAssignedAttackerToAttackTarget={0} läßt {1} {2} angreifen. lblLogPlayerAssignedAttackerToAttackTarget={0} läßt {1} {2} angreifen.
lblLogPlayerDidntBlockAttacker={0} hat {1} nicht geblockt. lblLogPlayerDidntBlockAttacker={0} hat {1} nicht geblockt.
lblLogPlayerAssignedBlockerToBlockAttacker={0} läßt {1} {2} blocken. lblLogPlayerAssignedBlockerToBlockAttacker={0} läßt {1} {2} blocken.
@@ -2035,6 +2037,8 @@ lblChooseCardToManifest=Wähle zu manifestierende Karte
lblChooseCardToMeld=Wähle Karte zum Verschmelzen mit lblChooseCardToMeld=Wähle Karte zum Verschmelzen mit
#MillEffect.java #MillEffect.java
lblDoYouWantToMill=Willst du {0} millen?{1} lblDoYouWantToMill=Willst du {0} millen?{1}
lblMilledToZone=(zu {0})
lblMilledCards=Karten {0} gefräst
#MultiplePilesEffect.java #MultiplePilesEffect.java
lblChooseCardsInTargetPile=Wähle Karten in Stapel {0}? lblChooseCardsInTargetPile=Wähle Karten in Stapel {0}?
#MutateEffect.java #MutateEffect.java

View File

@@ -1512,6 +1512,8 @@ lblCombat=combat
lblNonCombat=non-combat lblNonCombat=non-combat
lblLogSourceDealsNDamageOfTypeToDest={0} deals {1} {2} damage to {3}{4}. lblLogSourceDealsNDamageOfTypeToDest={0} deals {1} {2} damage to {3}{4}.
lblLogPlayerReceivesNPosionCounterFrom={0} receives {1} poison counter from {2} lblLogPlayerReceivesNPosionCounterFrom={0} receives {1} poison counter from {2}
lblLogPlayerRadiation={0} gets {1} from {2}.
lblLogPlayerRadRemove={0} removes {1} due to {2}.
lblLogPlayerAssignedAttackerToAttackTarget={0} assigned {1} to attack {2}. lblLogPlayerAssignedAttackerToAttackTarget={0} assigned {1} to attack {2}.
lblLogPlayerDidntBlockAttacker={0} didn''t block {1}. lblLogPlayerDidntBlockAttacker={0} didn''t block {1}.
lblLogPlayerAssignedBlockerToBlockAttacker={0} assigned {1} to block {2}. lblLogPlayerAssignedBlockerToBlockAttacker={0} assigned {1} to block {2}.
@@ -2040,6 +2042,8 @@ lblChooseCardToManifest=Choose cards to manifest
lblChooseCardToMeld=Choose card to meld with lblChooseCardToMeld=Choose card to meld with
#MillEffect.java #MillEffect.java
lblDoYouWantToMill=Do you want to mill {0}?{1} lblDoYouWantToMill=Do you want to mill {0}?{1}
lblMilledToZone=(to {0})
lblMilledCards=Cards {0} milled
#MultiplePilesEffect.java #MultiplePilesEffect.java
lblChooseCardsInTargetPile=Choose cards in Pile {0}? lblChooseCardsInTargetPile=Choose cards in Pile {0}?
#MutateEffect.java #MutateEffect.java

View File

@@ -1508,6 +1508,8 @@ lblCombat=combate
lblNonCombat=no combate lblNonCombat=no combate
lblLogSourceDealsNDamageOfTypeToDest={0} hace {1} punto(s) de daño de {2} a {3}{4}. lblLogSourceDealsNDamageOfTypeToDest={0} hace {1} punto(s) de daño de {2} a {3}{4}.
lblLogPlayerReceivesNPosionCounterFrom={0} recibe {1} contador de veneno de {2} lblLogPlayerReceivesNPosionCounterFrom={0} recibe {1} contador de veneno de {2}
lblLogPlayerRadiation={0} obtiene {1} de {2}.
lblLogPlayerRadRemove={0} elimina {1} debido a {2}.
lblLogPlayerAssignedAttackerToAttackTarget={0} asigna a {1} para atacar a {2}. lblLogPlayerAssignedAttackerToAttackTarget={0} asigna a {1} para atacar a {2}.
lblLogPlayerDidntBlockAttacker={0} no bloquea a {1}. lblLogPlayerDidntBlockAttacker={0} no bloquea a {1}.
lblLogPlayerAssignedBlockerToBlockAttacker={0} asigna {1} para bloquear a {2}. lblLogPlayerAssignedBlockerToBlockAttacker={0} asigna {1} para bloquear a {2}.
@@ -2036,6 +2038,8 @@ lblChooseCardToManifest=Elige las cartas para manifestar
lblChooseCardToMeld=Elige una carta para fundirla con lblChooseCardToMeld=Elige una carta para fundirla con
#MillEffect.java #MillEffect.java
lblDoYouWantToMill=¿Quieres miller {0}?{1} lblDoYouWantToMill=¿Quieres miller {0}?{1}
lblMilledToZone=(a {0})
lblMilledCards=Tarjetas {0} fresadas
#MultiplePilesEffect.java #MultiplePilesEffect.java
lblChooseCardsInTargetPile=¿Elegir las cartas en la Pila {0}? lblChooseCardsInTargetPile=¿Elegir las cartas en la Pila {0}?
#MutateEffect.java #MutateEffect.java

View File

@@ -1511,6 +1511,8 @@ lblCombat=combat
lblNonCombat=sans combat lblNonCombat=sans combat
lblLogSourceDealsNDamageOfTypeToDest={0} inflige {1} {2} dégâts à {3}{4}. lblLogSourceDealsNDamageOfTypeToDest={0} inflige {1} {2} dégâts à {3}{4}.
lblLogPlayerReceivesNPosionCounterFrom={0} reçoit {1} marqueur de poison de {2} lblLogPlayerReceivesNPosionCounterFrom={0} reçoit {1} marqueur de poison de {2}
lblLogPlayerRadiation={0} obtient {1} de {2}.
lblLogPlayerRadRemove={0} supprime {1} en raison de {2}.
lblLogPlayerAssignedAttackerToAttackTarget={0} a assigné {1} pour attaquer {2}. lblLogPlayerAssignedAttackerToAttackTarget={0} a assigné {1} pour attaquer {2}.
lblLogPlayerDidntBlockAttacker={0} n''a pas bloqué {1}. lblLogPlayerDidntBlockAttacker={0} n''a pas bloqué {1}.
lblLogPlayerAssignedBlockerToBlockAttacker={0} a assigné {1} au bloc {2}. lblLogPlayerAssignedBlockerToBlockAttacker={0} a assigné {1} au bloc {2}.
@@ -2040,6 +2042,8 @@ lblChooseCardToManifest=Choisir les cartes à manifester
lblChooseCardToMeld=Choisissez la carte avec laquelle fusionner lblChooseCardToMeld=Choisissez la carte avec laquelle fusionner
#MillEffect.java #MillEffect.java
lblDoYouWantToMill=Voulez-vous meuler {0}?{1} lblDoYouWantToMill=Voulez-vous meuler {0}?{1}
lblMilledToZone=(à {0})
lblMilledCards=Cartes {0} fraisées
#MultiplePilesEffect.java #MultiplePilesEffect.java
lblChooseCardsInTargetPile=Choisir les cartes dans la pile {0} ? lblChooseCardsInTargetPile=Choisir les cartes dans la pile {0} ?
#MutateEffect.java #MutateEffect.java

View File

@@ -1508,6 +1508,8 @@ lblCombat=da combattimento
lblNonCombat=non da combattimento lblNonCombat=non da combattimento
lblLogSourceDealsNDamageOfTypeToDest={0} infligge {1} {2} danno/i a {3}{4}. lblLogSourceDealsNDamageOfTypeToDest={0} infligge {1} {2} danno/i a {3}{4}.
lblLogPlayerReceivesNPosionCounterFrom={0} riceve {1} segnalino/i veleno da {2} lblLogPlayerReceivesNPosionCounterFrom={0} riceve {1} segnalino/i veleno da {2}
lblLogPlayerRadiation={0} ottiene {1} da {2}.
lblLogPlayerRadRemove={0} rimuove {1} a causa di {2}.
lblLogPlayerAssignedAttackerToAttackTarget={0} ha dichiarato di attaccare {2} con {1}. lblLogPlayerAssignedAttackerToAttackTarget={0} ha dichiarato di attaccare {2} con {1}.
lblLogPlayerDidntBlockAttacker={0} non blocca {1}. lblLogPlayerDidntBlockAttacker={0} non blocca {1}.
lblLogPlayerAssignedBlockerToBlockAttacker={0} ha dichiarato di bloccare {2} con {1}. lblLogPlayerAssignedBlockerToBlockAttacker={0} ha dichiarato di bloccare {2} con {1}.
@@ -2036,6 +2038,8 @@ lblChooseCardToManifest=Scegli le carte da manifestare
lblChooseCardToMeld=Scegli le carte da combinare lblChooseCardToMeld=Scegli le carte da combinare
#MillEffect.java #MillEffect.java
lblDoYouWantToMill=Vuoi macinare {0}?{1} lblDoYouWantToMill=Vuoi macinare {0}?{1}
lblMilledToZone=(a {0})
lblMilledCards=Carte {0} macinate
#MultiplePilesEffect.java #MultiplePilesEffect.java
lblChooseCardsInTargetPile=Scegli le carte nella Pila {0}? lblChooseCardsInTargetPile=Scegli le carte nella Pila {0}?
#MutateEffect.java #MutateEffect.java

View File

@@ -1509,6 +1509,8 @@ lblCombat=戦闘
lblNonCombat=非戦闘 lblNonCombat=非戦闘
lblLogSourceDealsNDamageOfTypeToDest={0}は {3}{4}に対して{1} {2}点のダメージを与えました。 lblLogSourceDealsNDamageOfTypeToDest={0}は {3}{4}に対して{1} {2}点のダメージを与えました。
lblLogPlayerReceivesNPosionCounterFrom={0}は {2}から {1}個毒カウンターを貰いました。 lblLogPlayerReceivesNPosionCounterFrom={0}は {2}から {1}個毒カウンターを貰いました。
lblLogPlayerRadiation={0}{2}から{1}を得ます。
lblLogPlayerRadRemove={0}は、{2}による{1}を削除します。
lblLogPlayerAssignedAttackerToAttackTarget={0}は {1}を {2}の攻撃に指定しました。 lblLogPlayerAssignedAttackerToAttackTarget={0}は {1}を {2}の攻撃に指定しました。
lblLogPlayerDidntBlockAttacker={0}が {1}をブロックしていません。 lblLogPlayerDidntBlockAttacker={0}が {1}をブロックしていません。
lblLogPlayerAssignedBlockerToBlockAttacker={0}は {1}を {2}のブロックに指定しました。 lblLogPlayerAssignedBlockerToBlockAttacker={0}は {1}を {2}のブロックに指定しました。
@@ -2035,6 +2037,8 @@ lblChooseCardToManifest=予示するカードを選ぶ
lblChooseCardToMeld=合体するカードを選ぶ lblChooseCardToMeld=合体するカードを選ぶ
#MillEffect.java #MillEffect.java
lblDoYouWantToMill={0}を製粉したいですか?{1} lblDoYouWantToMill={0}を製粉したいですか?{1}
lblMilledToZone=({0} まで)
lblMilledCards=カード{0}ミリング
#MultiplePilesEffect.java #MultiplePilesEffect.java
lblChooseCardsInTargetPile={0}番目の束からカードを選びますか? lblChooseCardsInTargetPile={0}番目の束からカードを選びますか?
#MutateEffect.java #MutateEffect.java

View File

@@ -1544,6 +1544,8 @@ lblCombat=combate
lblNonCombat=não-combate lblNonCombat=não-combate
lblLogSourceDealsNDamageOfTypeToDest={0} causa {1} {2} de dano a {3}{4}. lblLogSourceDealsNDamageOfTypeToDest={0} causa {1} {2} de dano a {3}{4}.
lblLogPlayerReceivesNPosionCounterFrom={0} recebe {1} contador de veneno de {2} lblLogPlayerReceivesNPosionCounterFrom={0} recebe {1} contador de veneno de {2}
lblLogPlayerRadiation={0} obtém {1} de {2}.
lblLogPlayerRadRemove={0} remove {1} devido a {2}.
lblLogPlayerAssignedAttackerToAttackTarget={0} atribuiu {1} para atacar {2}. lblLogPlayerAssignedAttackerToAttackTarget={0} atribuiu {1} para atacar {2}.
lblLogPlayerDidntBlockAttacker={0} não bloqueou {1}. lblLogPlayerDidntBlockAttacker={0} não bloqueou {1}.
lblLogPlayerAssignedBlockerToBlockAttacker={0} atribuiu {1} para bloquear {2}. lblLogPlayerAssignedBlockerToBlockAttacker={0} atribuiu {1} para bloquear {2}.
@@ -2097,6 +2099,8 @@ lblChooseCardToManifest=Escolha cartas para manifestar
lblChooseCardToMeld=Escolha a carta para fundir com lblChooseCardToMeld=Escolha a carta para fundir com
#MillEffect.java #MillEffect.java
lblDoYouWantToMill=Você quer moer {0}?{1} lblDoYouWantToMill=Você quer moer {0}?{1}
lblMilledToZone=(para {0})
lblMilledCards=Cartões {0} fresados
#MultiplePilesEffect.java #MultiplePilesEffect.java
lblChooseCardsInTargetPile=Escolha cartas na pilha {0}? lblChooseCardsInTargetPile=Escolha cartas na pilha {0}?
#MutateEffect.java #MutateEffect.java

View File

@@ -1512,6 +1512,8 @@ lblCombat=战斗
lblNonCombat=非战斗 lblNonCombat=非战斗
lblLogSourceDealsNDamageOfTypeToDest={0}对{3}造成{1}点{2}伤害{4}。 lblLogSourceDealsNDamageOfTypeToDest={0}对{3}造成{1}点{2}伤害{4}。
lblLogPlayerReceivesNPosionCounterFrom={0}获得来自{2}的{1}个中毒指示物 lblLogPlayerReceivesNPosionCounterFrom={0}获得来自{2}的{1}个中毒指示物
lblLogPlayerRadiation={0}从{2}那里得到{1}。
lblLogPlayerRadRemove={0}消除了由于{2}而产生的{1}。
lblLogPlayerAssignedAttackerToAttackTarget={0}已分配{1}进攻{2}。 lblLogPlayerAssignedAttackerToAttackTarget={0}已分配{1}进攻{2}。
lblLogPlayerDidntBlockAttacker={0}没有阻挡{1}. lblLogPlayerDidntBlockAttacker={0}没有阻挡{1}.
lblLogPlayerAssignedBlockerToBlockAttacker={0}已分配{1}对{2}进行阻挡。 lblLogPlayerAssignedBlockerToBlockAttacker={0}已分配{1}对{2}进行阻挡。
@@ -2040,6 +2042,8 @@ lblChooseCardToManifest=选择要显化的牌
lblChooseCardToMeld=选择要融合的牌 lblChooseCardToMeld=选择要融合的牌
#MillEffect.java #MillEffect.java
lblDoYouWantToMill=您想铣削{0}吗?{1} lblDoYouWantToMill=您想铣削{0}吗?{1}
lblMilledToZone=(到{0})
lblMilledCards=卡{0}铣削
#MultiplePilesEffect.java #MultiplePilesEffect.java
lblChooseCardsInTargetPile=选择堆{0}中的牌? lblChooseCardsInTargetPile=选择堆{0}中的牌?
#MutateEffect.java #MutateEffect.java

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@@ -505,6 +505,11 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
return processPlayer(event.receiver, livesUpdate); return processPlayer(event.receiver, livesUpdate);
} }
@Override
public Void visit(final GameEventPlayerRadiation event) {
return processPlayer(event.receiver, livesUpdate);
}
@Override @Override
public Void visit(final GameEventPlayerDamaged event) { public Void visit(final GameEventPlayerDamaged event) {
return processEvent(); return processEvent();

View File

@@ -90,6 +90,7 @@ public enum FSkinProp {
IMG_ZONE_POISON (new int[] {320, 80, 40, 40}, PropType.IMAGE), IMG_ZONE_POISON (new int[] {320, 80, 40, 40}, PropType.IMAGE),
IMG_TICKET (new int[] {360, 80, 40, 40}, PropType.IMAGE), IMG_TICKET (new int[] {360, 80, 40, 40}, PropType.IMAGE),
IMG_RAD (new int[] {360, 120, 40, 40}, PropType.IMAGE),
//mana images //mana images
IMG_MANA_B (new int[] {166, 2, 80, 80}, PropType.MANAICONS), IMG_MANA_B (new int[] {166, 2, 80, 80}, PropType.MANAICONS),

View File

@@ -939,22 +939,20 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
} }
@Override @Override
public void reveal(final CardCollectionView cards, final ZoneType zone, final Player owner, String message) { public void reveal(final CardCollectionView cards, final ZoneType zone, final Player owner, String message, boolean addSuffix) {
reveal(cards, zone, PlayerView.get(owner), message); reveal(cards, zone, PlayerView.get(owner), message, addSuffix);
} }
@Override @Override
public void reveal(final List<CardView> cards, final ZoneType zone, final PlayerView owner, String message) { public void reveal(final List<CardView> cards, final ZoneType zone, final PlayerView owner, String message, boolean addSuffix) {
reveal(getCardList(cards), zone, owner, message); reveal(getCardList(cards), zone, owner, message, addSuffix);
} }
protected void reveal(final CardCollectionView cards, final ZoneType zone, final PlayerView owner, String message) { protected void reveal(final CardCollectionView cards, final ZoneType zone, final PlayerView owner, String message, boolean addSuffix) {
if (StringUtils.isBlank(message)) { if (StringUtils.isBlank(message)) {
message = localizer.getMessage("lblLookCardInPlayerZone", "{player's}", zone.getTranslatedName().toLowerCase()); message = localizer.getMessage("lblLookCardInPlayerZone", "{player's}", zone.getTranslatedName().toLowerCase());
} else if (message.startsWith("OVERRIDE")) {
message = message.substring(9);
} else { } else {
message += " " + localizer.getMessage("lblPlayerZone", "{player's}", zone.getTranslatedName().toLowerCase()); if (addSuffix) message += " " + localizer.getMessage("lblPlayerZone", "{player's}", zone.getTranslatedName().toLowerCase());
} }
final String fm = MessageUtil.formatMessage(message, getLocalPlayerView(), owner); final String fm = MessageUtil.formatMessage(message, getLocalPlayerView(), owner);
if (!cards.isEmpty()) { if (!cards.isEmpty()) {