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
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) {
AiCardMemory.rememberCard(player, c, AiCardMemory.MemorySet.REVEALED_CARDS);
}
}
@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) {
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.PutCounter, CountersPutAi.class)
.put(ApiType.PutCounterAll, CountersPutAllAi.class)
.put(ApiType.Radiation, AlwaysPlayAi.class)
.put(ApiType.RearrangeTopOfLibrary, RearrangeTopOfLibraryAi.class)
.put(ApiType.Regenerate, RegenerateAi.class)
.put(ApiType.RegenerateAll, RegenerateAllAi.class)

View File

@@ -1926,15 +1926,15 @@ public class GameAction {
revealTo(cards, to, null);
}
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) {
revealTo(new CardCollection(card), 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()) {
return;
}
@@ -1942,7 +1942,7 @@ public class GameAction {
final ZoneType zone = cards.getFirst().getZone().getZoneType();
final Player owner = cards.getFirst().getOwner();
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);
}
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);
if (firstCard == null) {
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) {
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()) {
if (dontRevealToOwner && cardOwner == p) {
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.game.card.Card;
import forge.game.card.CounterEnumType;
import forge.game.event.*;
import forge.game.event.GameEventCardDamaged.DamageType;
import forge.game.player.Player;
@@ -224,6 +225,21 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
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
public GameLogEntry visit(final GameEventAttackersDeclared ev) {
final StringBuilder sb = new StringBuilder();

View File

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

View File

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

View File

@@ -88,7 +88,6 @@ public class ClashEffect extends SpellAbilityEffect {
}
final StringBuilder reveal = new StringBuilder();
reveal.append("OVERRIDE "); //will return substring with the original message parsed here..
Card pCard = null;
Card oCard = null;
final CardCollection toReveal = new CardCollection();
@@ -122,7 +121,7 @@ public class ClashEffect extends SpellAbilityEffect {
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(opponent, oCard, sa);

View File

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

View File

@@ -427,6 +427,8 @@ public enum CounterEnumType {
POISON("POISN"),
RAD("RAD"),
TICKET("TICKET"),
// 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(GameEventPlayerCounters event);
T visit(GameEventPlayerPoisoned event);
T visit(GameEventPlayerRadiation event);
T visit(GameEventPlayerPriority event);
T visit(GameEventPlayerShardsChanged event);
T visit(GameEventPlayerStatsChanged event);
@@ -90,6 +91,7 @@ public interface IGameEventVisitor<T> {
public T visit(GameEventPlayerControl event) { return null; }
public T visit(GameEventPlayerCounters 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(GameEventPlayerShardsChanged event) { return null; }
public T visit(GameEventPlayerStatsChanged event) { return null; }

View File

@@ -17,43 +17,22 @@
*/
package forge.game.phase;
import java.util.*;
import com.google.common.collect.*;
import org.apache.commons.lang3.time.StopWatch;
import forge.game.Game;
import forge.game.GameEntity;
import forge.game.GameEntityCounterTable;
import forge.game.GameStage;
import forge.game.GameType;
import forge.game.GlobalRuleChange;
import com.google.common.base.Predicates;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import forge.game.*;
import forge.game.ability.AbilityKey;
import forge.game.ability.effects.AddTurnEffect;
import forge.game.ability.effects.SkipPhaseEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardUtil;
import forge.game.card.*;
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.CombatUtil;
import forge.game.cost.CostEnlist;
import forge.game.cost.CostExert;
import forge.game.event.GameEventAttackersDeclared;
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.event.*;
import forge.game.player.Player;
import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType;
@@ -64,9 +43,14 @@ import forge.game.trigger.TriggerType;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.util.CollectionSuppliers;
import forge.util.Lang;
import forge.util.Localizer;
import forge.util.TextUtil;
import forge.util.maps.HashMapOfLists;
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()) {
playerTurn.setSchemeInMotion();
}
if (playerTurn.hasRadiationEffect()) {
handleRadiation();
}
GameEntityCounterTable table = new GameEntityCounterTable();
// all Saga get Lore counter at the begin of pre combat
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() {
final Player whoDeclares = playerDeclaresAttackers == null || playerDeclaresAttackers.hasLost()
? playerTurn

View File

@@ -17,39 +17,9 @@
*/
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.Predicates;
import com.google.common.collect.ImmutableList;
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 com.google.common.collect.*;
import forge.ImageKeys;
import forge.LobbyPlayer;
import forge.card.CardStateName;
@@ -58,36 +28,17 @@ import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard;
import forge.game.CardTraitBase;
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.*;
import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.effects.DetachedCardEffect;
import forge.game.card.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.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil;
import forge.game.card.CardZoneTable;
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.event.*;
import forge.game.keyword.*;
import forge.game.keyword.KeywordCollection.KeywordCollectionView;
import forge.game.keyword.KeywordInterface;
import forge.game.keyword.KeywordsChange;
import forge.game.mana.ManaPool;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
@@ -95,16 +46,10 @@ import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementHandler;
import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.LandAbility;
import forge.game.spellability.SpellAbility;
import forge.game.staticability.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.staticability.*;
import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerHandler;
import forge.game.trigger.TriggerType;
@@ -114,13 +59,14 @@ import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.item.IPaperCard;
import forge.item.PaperCard;
import forge.util.Aggregates;
import forge.util.Lang;
import forge.util.Localizer;
import forge.util.MyRandom;
import forge.util.TextUtil;
import forge.util.*;
import forge.util.collect.FCollection;
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>
@@ -240,6 +186,8 @@ public class Player extends GameEntity implements Comparable<Player> {
private Card monarchEffect;
private Card initiativeEffect;
private Card blessingEffect;
private Card radiationEffect;
private Card keywordEffect;
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));
}
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
public final int getPoisonCounters() {
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() {
if (getKeywordCard() == null)
return;
@@ -3735,7 +3731,7 @@ public class Player extends GameEntity implements Comparable<Player> {
lki.setZone(c.getZone());
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) {
reveal(cards, zone, owner, null);
}
public abstract void reveal(CardCollectionView cards, ZoneType zone, Player owner, String messagePrefix);
public abstract void reveal(List<CardView> cards, ZoneType zone, PlayerView owner, String messagePrefix);
public final void reveal(CardCollectionView cards, ZoneType zone, Player 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 */
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.Amount, cards.size());
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 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 lblRad = new FLabel.Builder().fontAlign(SwingConstants.CENTER).fontStyle(Font.BOLD).icon(FSkin.getImage(FSkinProp.IMG_RAD)).iconInBackground().build();
private final PhaseIndicator phaseIndicator = new PhaseIndicator();
@@ -115,6 +116,7 @@ public class VField implements IVDoc<CField> {
lblEnergy.setFocusable(false);
lblExperience.setFocusable(false);
lblTicket.setFocusable(false);
lblRad.setFocusable(false);
avatarArea.setOpaque(false);
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");
}
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() {
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 energy = player.getCounters(CounterEnumType.ENERGY);
final int experience = player.getCounters(CounterEnumType.EXPERIENCE);
final int rad = player.getCounters(CounterEnumType.RAD);
final int ticket = player.getCounters(CounterEnumType.TICKET);
if (poison > 0) {
removeLblEnergy();
removeLblExperience();
removeLblRad();
removeLblTicket();
addLblPoison();
lblPoison.setText(String.valueOf(poison));
@@ -326,6 +348,7 @@ public class VField implements IVDoc<CField> {
if (energy > 0) {
removeLblExperience();
removeLblRad();
removeLblTicket();
if (poison == 0) {
addLblEnergy();
@@ -336,6 +359,7 @@ public class VField implements IVDoc<CField> {
}
if (experience > 0) {
removeLblRad();
removeLblTicket();
if (poison == 0 && energy == 0) {
addLblExperience();
@@ -345,8 +369,18 @@ public class VField implements IVDoc<CField> {
removeLblExperience();
}
if (ticket > 0) {
if (rad > 0) {
removeLblTicket();
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();
lblTicket.setText(String.valueOf(ticket));
}

View File

@@ -239,12 +239,12 @@ public class PlayerControllerForTests extends PlayerController {
}
@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
}
@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
}

View File

@@ -146,6 +146,7 @@ public enum FSkinImage implements FImage {
COUNTERS_MULTI (FSkinProp.IMG_COUNTERS_MULTI, SourceFile.ICONS),
ENERGY (FSkinProp.IMG_ENERGY, SourceFile.ICONS),
TICKET (FSkinProp.IMG_TICKET, SourceFile.ICONS),
RAD (FSkinProp.IMG_RAD, SourceFile.ICONS),
//Dock 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 experienceCounters = player.getCounters(CounterEnumType.EXPERIENCE);
private int ticketCounters = player.getCounters(CounterEnumType.TICKET);
private int radCounters = player.getCounters(CounterEnumType.RAD);
private int manaShards = player.getNumManaShards();
private String lifeStr = String.valueOf(life);
@@ -525,7 +526,7 @@ public class VPlayerPanel extends FContainer {
adjustHeight = 1;
float divider = Gdx.app.getGraphics().getHeight() > 900 ? 1.2f : 2f;
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.drawText(lifeStr, INFO2_FONT, getInfoForeColor().getColor(), 0, 0, getWidth(), getHeight(), false, Align.left, false);
} 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);
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) {
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);

View File

@@ -1,7 +1,7 @@
Name:Death Ring
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.
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: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

View File

@@ -1,6 +1,6 @@
Name:Call to the Void
ManaCost:4 B
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
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.
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: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: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.

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:DBMake:DB$ MakeCard | Name$ ChosenName | Zone$ None | RememberMade$ True | SubAbility$ DBClearNamed
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: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

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
lblLogSourceDealsNDamageOfTypeToDest={0} verursacht {1} {2} Schaden bei {3}{4}.
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.
lblLogPlayerDidntBlockAttacker={0} hat {1} nicht geblockt.
lblLogPlayerAssignedBlockerToBlockAttacker={0} läßt {1} {2} blocken.
@@ -2035,6 +2037,8 @@ lblChooseCardToManifest=Wähle zu manifestierende Karte
lblChooseCardToMeld=Wähle Karte zum Verschmelzen mit
#MillEffect.java
lblDoYouWantToMill=Willst du {0} millen?{1}
lblMilledToZone=(zu {0})
lblMilledCards=Karten {0} gefräst
#MultiplePilesEffect.java
lblChooseCardsInTargetPile=Wähle Karten in Stapel {0}?
#MutateEffect.java

View File

@@ -1512,6 +1512,8 @@ lblCombat=combat
lblNonCombat=non-combat
lblLogSourceDealsNDamageOfTypeToDest={0} deals {1} {2} damage to {3}{4}.
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}.
lblLogPlayerDidntBlockAttacker={0} didn''t block {1}.
lblLogPlayerAssignedBlockerToBlockAttacker={0} assigned {1} to block {2}.
@@ -2040,6 +2042,8 @@ lblChooseCardToManifest=Choose cards to manifest
lblChooseCardToMeld=Choose card to meld with
#MillEffect.java
lblDoYouWantToMill=Do you want to mill {0}?{1}
lblMilledToZone=(to {0})
lblMilledCards=Cards {0} milled
#MultiplePilesEffect.java
lblChooseCardsInTargetPile=Choose cards in Pile {0}?
#MutateEffect.java

View File

@@ -1508,6 +1508,8 @@ lblCombat=combate
lblNonCombat=no combate
lblLogSourceDealsNDamageOfTypeToDest={0} hace {1} punto(s) de daño de {2} a {3}{4}.
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}.
lblLogPlayerDidntBlockAttacker={0} no bloquea a {1}.
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
#MillEffect.java
lblDoYouWantToMill=¿Quieres miller {0}?{1}
lblMilledToZone=(a {0})
lblMilledCards=Tarjetas {0} fresadas
#MultiplePilesEffect.java
lblChooseCardsInTargetPile=¿Elegir las cartas en la Pila {0}?
#MutateEffect.java

View File

@@ -1511,6 +1511,8 @@ lblCombat=combat
lblNonCombat=sans combat
lblLogSourceDealsNDamageOfTypeToDest={0} inflige {1} {2} dégâts à {3}{4}.
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}.
lblLogPlayerDidntBlockAttacker={0} n''a pas bloqué {1}.
lblLogPlayerAssignedBlockerToBlockAttacker={0} a assigné {1} au bloc {2}.
@@ -2040,6 +2042,8 @@ lblChooseCardToManifest=Choisir les cartes à manifester
lblChooseCardToMeld=Choisissez la carte avec laquelle fusionner
#MillEffect.java
lblDoYouWantToMill=Voulez-vous meuler {0}?{1}
lblMilledToZone=(à {0})
lblMilledCards=Cartes {0} fraisées
#MultiplePilesEffect.java
lblChooseCardsInTargetPile=Choisir les cartes dans la pile {0} ?
#MutateEffect.java

View File

@@ -1508,6 +1508,8 @@ lblCombat=da combattimento
lblNonCombat=non da combattimento
lblLogSourceDealsNDamageOfTypeToDest={0} infligge {1} {2} danno/i a {3}{4}.
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}.
lblLogPlayerDidntBlockAttacker={0} non blocca {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
#MillEffect.java
lblDoYouWantToMill=Vuoi macinare {0}?{1}
lblMilledToZone=(a {0})
lblMilledCards=Carte {0} macinate
#MultiplePilesEffect.java
lblChooseCardsInTargetPile=Scegli le carte nella Pila {0}?
#MutateEffect.java

View File

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

View File

@@ -1544,6 +1544,8 @@ lblCombat=combate
lblNonCombat=não-combate
lblLogSourceDealsNDamageOfTypeToDest={0} causa {1} {2} de dano a {3}{4}.
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}.
lblLogPlayerDidntBlockAttacker={0} não bloqueou {1}.
lblLogPlayerAssignedBlockerToBlockAttacker={0} atribuiu {1} para bloquear {2}.
@@ -2097,6 +2099,8 @@ lblChooseCardToManifest=Escolha cartas para manifestar
lblChooseCardToMeld=Escolha a carta para fundir com
#MillEffect.java
lblDoYouWantToMill=Você quer moer {0}?{1}
lblMilledToZone=(para {0})
lblMilledCards=Cartões {0} fresados
#MultiplePilesEffect.java
lblChooseCardsInTargetPile=Escolha cartas na pilha {0}?
#MutateEffect.java

View File

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

View File

@@ -90,6 +90,7 @@ public enum FSkinProp {
IMG_ZONE_POISON (new int[] {320, 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
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
public void reveal(final CardCollectionView cards, final ZoneType zone, final Player owner, String message) {
reveal(cards, zone, PlayerView.get(owner), message);
public void reveal(final CardCollectionView cards, final ZoneType zone, final Player owner, String message, boolean addSuffix) {
reveal(cards, zone, PlayerView.get(owner), message, addSuffix);
}
@Override
public void reveal(final List<CardView> cards, final ZoneType zone, final PlayerView owner, String message) {
reveal(getCardList(cards), zone, owner, message);
public void reveal(final List<CardView> cards, final ZoneType zone, final PlayerView owner, String message, boolean addSuffix) {
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)) {
message = localizer.getMessage("lblLookCardInPlayerZone", "{player's}", zone.getTranslatedName().toLowerCase());
} else if (message.startsWith("OVERRIDE")) {
message = message.substring(9);
} 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);
if (!cards.isEmpty()) {