mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
- Counters moved from being on Card to on GameEntity allowing Poison + Experience Counters to work the same as other counter types
- Improved some PlayerView updates which weren't re-writing player detail hoverbox often enough
This commit is contained in:
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -548,6 +548,7 @@ forge-game/src/main/java/forge/game/event/GameEventManaBurn.java -text
|
||||
forge-game/src/main/java/forge/game/event/GameEventManaPool.java -text
|
||||
forge-game/src/main/java/forge/game/event/GameEventMulligan.java -text
|
||||
forge-game/src/main/java/forge/game/event/GameEventPlayerControl.java -text
|
||||
forge-game/src/main/java/forge/game/event/GameEventPlayerCounters.java -text
|
||||
forge-game/src/main/java/forge/game/event/GameEventPlayerDamaged.java -text
|
||||
forge-game/src/main/java/forge/game/event/GameEventPlayerLivesChanged.java -text
|
||||
forge-game/src/main/java/forge/game/event/GameEventPlayerPoisoned.java -text
|
||||
@@ -4300,6 +4301,7 @@ forge-gui/res/cardsfolder/d/dawnstrider.txt svneol=native#text/plain
|
||||
forge-gui/res/cardsfolder/d/dawnstrike_paladin.txt -text
|
||||
forge-gui/res/cardsfolder/d/dawntreader_elk.txt -text
|
||||
forge-gui/res/cardsfolder/d/daxos_of_meletis.txt -text
|
||||
forge-gui/res/cardsfolder/d/daxos_the_returned.txt -text
|
||||
forge-gui/res/cardsfolder/d/day_of_destiny.txt svneol=native#text/plain
|
||||
forge-gui/res/cardsfolder/d/day_of_judgment.txt svneol=native#text/plain
|
||||
forge-gui/res/cardsfolder/d/day_of_the_dragons.txt svneol=native#text/plain
|
||||
|
||||
@@ -1485,8 +1485,15 @@ public class AiController {
|
||||
}
|
||||
|
||||
for (Player e : enemies) {
|
||||
if (e.getPoisonCounters() > 0) {
|
||||
result.put(e, null); // poison counter type is hardcoded at data consumer's side (this works while players may have no other counters)
|
||||
// TODO In the future check of enemies can get poison counters and give them some other bad counter type
|
||||
if (e.getCounters(CounterType.POISON) > 0) {
|
||||
result.put(e, CounterType.POISON);
|
||||
}
|
||||
}
|
||||
|
||||
for (Player pl : allies) {
|
||||
if (pl.getCounters(CounterType.EXPERIENCE) > 0) {
|
||||
result.put(pl, CounterType.EXPERIENCE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ package forge.game;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.event.GameEventCardAttachment;
|
||||
import forge.game.event.GameEventCardAttachment.AttachMethod;
|
||||
import forge.util.collect.FCollection;
|
||||
@@ -34,6 +35,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
private int preventNextDamage = 0;
|
||||
private CardCollection enchantedBy;
|
||||
private Map<Card, Map<String, String>> preventionShieldsWithEffects = new TreeMap<Card, Map<String, String>>();
|
||||
protected Map<CounterType, Integer> counters = new TreeMap<>();
|
||||
|
||||
protected GameEntity(int id0) {
|
||||
id = id0;
|
||||
@@ -198,6 +200,33 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
|
||||
public abstract boolean hasProtectionFrom(final Card source);
|
||||
|
||||
// Counters!
|
||||
public boolean hasCounters() {
|
||||
return !counters.isEmpty();
|
||||
}
|
||||
|
||||
// get all counters from a card
|
||||
public final Map<CounterType, Integer> getCounters() {
|
||||
return counters;
|
||||
}
|
||||
|
||||
public final int getCounters(final CounterType counterName) {
|
||||
Integer value = counters.get(counterName);
|
||||
return value == null ? 0 : value;
|
||||
}
|
||||
|
||||
public void setCounters(final CounterType counterType, final Integer num) {
|
||||
counters.put(counterType, num);
|
||||
}
|
||||
|
||||
abstract public void setCounters(final Map<CounterType, Integer> allCounters);
|
||||
|
||||
abstract public boolean canReceiveCounters(final CounterType type);
|
||||
abstract protected void addCounter(final CounterType counterType, final int n, final boolean applyMultiplier, final boolean fireEvents);
|
||||
abstract public void subtractCounter(final CounterType counterName, final int n);
|
||||
abstract public void clearCounters();
|
||||
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object o) {
|
||||
if (o == null) { return false; }
|
||||
|
||||
@@ -29,7 +29,7 @@ public class CountersProliferateEffect extends SpellAbilityEffect {
|
||||
return;
|
||||
for(Entry<GameEntity, CounterType> ge: proliferateChoice.entrySet()) {
|
||||
if( ge.getKey() instanceof Player )
|
||||
((Player) ge.getKey()).addPoisonCounters(1, sa.getHostCard());
|
||||
((Player) ge.getKey()).addCounter(ge.getValue(), 1, true);
|
||||
else if( ge.getKey() instanceof Card)
|
||||
((Card) ge.getKey()).addCounter(ge.getValue(), 1, true);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import forge.game.GameObject;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
@@ -95,15 +97,19 @@ public class CountersPutEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
CardCollection tgtCards = new CardCollection();
|
||||
List<GameObject> tgtObjects = Lists.newArrayList();
|
||||
if (sa.hasParam("Bolster")) {
|
||||
CardCollection creatsYouCtrl = CardLists.filter(activator.getCardsIn(ZoneType.Battlefield), Presets.CREATURES);
|
||||
CardCollection leastToughness = new CardCollection(Aggregates.listWithMin(creatsYouCtrl, CardPredicates.Accessors.fnGetDefense));
|
||||
tgtCards.addAll(activator.getController().chooseCardsForEffect(leastToughness, sa, "Choose a creature with the least toughness", 1, 1, false));
|
||||
tgtObjects.addAll(tgtCards);
|
||||
} else {
|
||||
tgtCards.addAll(getDefinedCardsOrTargeted(sa));
|
||||
tgtObjects.addAll(getDefinedOrTargeted(sa, "Defined"));
|
||||
}
|
||||
|
||||
for (final Card tgtCard : tgtCards) {
|
||||
for (final GameObject obj : tgtObjects) {
|
||||
if (obj instanceof Card) {
|
||||
Card tgtCard = (Card) obj;
|
||||
counterAmount = sa.usesTargeting() && sa.hasParam("DividedAsYouChoose") ? sa.getTargetRestrictions().getDividedValue(tgtCard) : counterAmount;
|
||||
if (!sa.usesTargeting() || tgtCard.canBeTargetedBy(sa)) {
|
||||
if (max != -1) {
|
||||
@@ -153,6 +159,11 @@ public class CountersPutEffect extends SpellAbilityEffect {
|
||||
tgtCard.addCounter(counterType, counterAmount, etbcounter);
|
||||
}
|
||||
}
|
||||
} else if (obj instanceof Player) {
|
||||
// Add Counters to players!
|
||||
Player pl = (Player) obj;
|
||||
pl.addCounter(counterType, counterAmount, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,6 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
private ZoneType castFrom = null;
|
||||
|
||||
private final CardDamageHistory damageHistory = new CardDamageHistory();
|
||||
private Map<CounterType, Integer> counters = new TreeMap<>();
|
||||
private Map<Card, Map<CounterType, Integer>> countersAddedBy = new TreeMap<>();
|
||||
private List<String> extrinsicKeyword = new ArrayList<>();
|
||||
// Hidden keywords won't be displayed on the card
|
||||
@@ -911,7 +910,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
addCounter(counterType, n, applyMultiplier, false);
|
||||
}
|
||||
|
||||
private void addCounter(final CounterType counterType, final int n, final boolean applyMultiplier, final boolean fireEvents) {
|
||||
protected void addCounter(final CounterType counterType, final int n, final boolean applyMultiplier, final boolean fireEvents) {
|
||||
int addAmount = n;
|
||||
if(addAmount < 0) {
|
||||
addAmount = 0; // As per rule 107.1b
|
||||
@@ -1043,20 +1042,6 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
}
|
||||
}
|
||||
|
||||
public final int getCounters(final CounterType counterName) {
|
||||
Integer value = counters.get(counterName);
|
||||
return value == null ? 0 : value;
|
||||
}
|
||||
|
||||
// get all counters from a card
|
||||
public final Map<CounterType, Integer> getCounters() {
|
||||
return counters;
|
||||
}
|
||||
|
||||
public final boolean hasCounters() {
|
||||
return !counters.isEmpty();
|
||||
}
|
||||
|
||||
public final void setCounters(final Map<CounterType, Integer> allCounters) {
|
||||
counters = allCounters;
|
||||
view.updateCounters(this);
|
||||
|
||||
@@ -1158,6 +1158,12 @@ public class CardFactoryUtil {
|
||||
return doXMath(c.getTotalDamageRecievedThisTurn(), m, c);
|
||||
}
|
||||
|
||||
if (sq[0].startsWith("YourCounters")) {
|
||||
// "YourCountersExperience" or "YourCountersPoison"
|
||||
String counterType = sq[0].substring(12);
|
||||
return doXMath(cc.getCounters(CounterType.getType(counterType)), m, c);
|
||||
}
|
||||
|
||||
if (sq[0].contains("YourPoisonCounters")) {
|
||||
return doXMath(cc.getPoisonCounters(), m, c);
|
||||
}
|
||||
|
||||
@@ -268,7 +268,13 @@ public enum CounterType {
|
||||
|
||||
WIND(),
|
||||
|
||||
WISH();
|
||||
WISH(),
|
||||
|
||||
// Player Counters
|
||||
|
||||
EXPERIENCE(),
|
||||
|
||||
POISON();
|
||||
|
||||
private String name;
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package forge.game.event;
|
||||
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.player.Player;
|
||||
|
||||
public class GameEventPlayerCounters extends GameEvent {
|
||||
public final Player receiver;
|
||||
public final CounterType type;
|
||||
public final int oldValue;
|
||||
public final int amount;
|
||||
|
||||
public GameEventPlayerCounters(Player recv, CounterType t, int old, int num) {
|
||||
receiver = recv;
|
||||
type = t;
|
||||
oldValue = old;
|
||||
amount = num;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ public interface IGameEventVisitor<T> {
|
||||
T visit(GameEventMulligan event);
|
||||
T visit(GameEventPlayerControl event);
|
||||
T visit(GameEventPlayerDamaged gameEventPlayerDamaged);
|
||||
T visit(GameEventPlayerCounters event);
|
||||
T visit(GameEventPlayerPoisoned event);
|
||||
T visit(GameEventPlayerPriority event);
|
||||
T visit(GameEventPlayerStatsChanged event);
|
||||
@@ -77,6 +78,7 @@ public interface IGameEventVisitor<T> {
|
||||
public T visit(GameEventManaBurn event) { return null; }
|
||||
public T visit(GameEventMulligan event) { return null; }
|
||||
public T visit(GameEventPlayerControl event) { return null; }
|
||||
public T visit(GameEventPlayerCounters event) { return null; }
|
||||
public T visit(GameEventPlayerPoisoned event) { return null; }
|
||||
public T visit(GameEventPlayerPriority event) { return null; }
|
||||
public T visit(GameEventPlayerStatsChanged event) { return null; }
|
||||
|
||||
@@ -32,12 +32,7 @@ import forge.game.ability.AbilityFactory;
|
||||
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.event.*;
|
||||
import forge.game.keyword.KeywordCollection;
|
||||
@@ -88,7 +83,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
private final Map<Card, Integer> commanderDamage = new HashMap<Card, Integer>();
|
||||
|
||||
private int poisonCounters = 0;
|
||||
private int life = 20;
|
||||
private int startingLife = 20;
|
||||
private final Map<Card, Integer> assignedDamage = new HashMap<Card, Integer>();
|
||||
@@ -853,25 +847,144 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return false;
|
||||
}
|
||||
|
||||
public final boolean canReceiveCounters(final CounterType type) {
|
||||
if (hasKeyword("PLAYER can't have counters placed on him or her.")) {
|
||||
return false;
|
||||
}
|
||||
if (type == CounterType.POISON) {
|
||||
if (hasKeyword("You can't get poison counters")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public final void addCounter(final CounterType counterType, final int n, final boolean applyMultiplier) {
|
||||
addCounter(counterType, n, applyMultiplier, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addCounter(CounterType counterType, int n, boolean applyMultiplier, boolean fireEvents) {
|
||||
if (!canReceiveCounters(counterType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int addAmount = n;
|
||||
if(addAmount <= 0) {
|
||||
// Can't add negative or 0 counters, bail out now
|
||||
return;
|
||||
}
|
||||
/* TODO Add Counter replacement if it ever effects Players
|
||||
final HashMap<String, Object> repParams = new HashMap<>();
|
||||
repParams.put("Event", "AddCounter");
|
||||
repParams.put("Affected", this);
|
||||
repParams.put("CounterType", counterType);
|
||||
repParams.put("CounterNum", addAmount);
|
||||
repParams.put("EffectOnly", applyMultiplier);
|
||||
if (getGame().getReplacementHandler().run(repParams) != ReplacementResult.NotReplaced) {
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
final int oldValue = getCounters(counterType);
|
||||
final int newValue = addAmount + oldValue;
|
||||
counters.put(counterType, newValue);
|
||||
view.updateCounters(this);
|
||||
|
||||
if (fireEvents) {
|
||||
getGame().fireEvent(new GameEventPlayerCounters(this, counterType, oldValue, newValue));
|
||||
}
|
||||
|
||||
/* TODO Run triggers when something cares
|
||||
final Map<String, Object> runParams = new TreeMap<>();
|
||||
runParams.put("Player", this);
|
||||
runParams.put("CounterType", counterType);
|
||||
for (int i = 0; i < addAmount; i++) {
|
||||
getGame().getTriggerHandler().runTrigger(TriggerType.CounterAdded, runParams, false);
|
||||
}
|
||||
if (addAmount > 0) {
|
||||
getGame().getTriggerHandler().runTrigger(TriggerType.CounterAddedOnce, runParams, false);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subtractCounter(CounterType counterName, int num) {
|
||||
int oldValue = getCounters(counterName);
|
||||
int newValue = Math.max(oldValue - num, 0);
|
||||
|
||||
final int delta = oldValue - newValue;
|
||||
if (delta == 0) { return; }
|
||||
|
||||
|
||||
if (newValue > 0) {
|
||||
counters.put(counterName, newValue);
|
||||
}
|
||||
else {
|
||||
counters.remove(counterName);
|
||||
}
|
||||
view.updateCounters(this);
|
||||
|
||||
getGame().fireEvent(new GameEventPlayerCounters(this, counterName, oldValue, newValue));
|
||||
|
||||
/* TODO Run triggers when something cares
|
||||
int curCounters = oldValue;
|
||||
for (int i = 0; i < delta && curCounters != 0; i++) {
|
||||
final Map<String, Object> runParams = new TreeMap<>();
|
||||
runParams.put("Card", this);
|
||||
runParams.put("CounterType", counterName);
|
||||
runParams.put("NewCounterAmount", --curCounters);
|
||||
getGame().getTriggerHandler().runTrigger(TriggerType.CounterRemoved, runParams, false);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public final void clearCounters() {
|
||||
if (counters.isEmpty()) { return; }
|
||||
counters.clear();
|
||||
view.updateCounters(this);
|
||||
getGame().fireEvent(new GameEventPlayerCounters(this, null, 0, 0));
|
||||
}
|
||||
|
||||
public void setCounters(final CounterType counterType, final Integer num) {
|
||||
counters.put(counterType, num);
|
||||
view.updateCounters(this);
|
||||
getGame().fireEvent(new GameEventPlayerCounters(this, counterType, 0, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCounters(Map<CounterType, Integer> allCounters) {
|
||||
counters = allCounters;
|
||||
view.updateCounters(this);
|
||||
getGame().fireEvent(new GameEventPlayerCounters(this, null, 0, 0));
|
||||
}
|
||||
|
||||
// TODO Merge These calls into the primary counter calls
|
||||
public final int getPoisonCounters() {
|
||||
return poisonCounters;
|
||||
return getCounters(CounterType.POISON);
|
||||
}
|
||||
public final void setPoisonCounters(final int num, Card source) {
|
||||
if (poisonCounters == num) { return; }
|
||||
|
||||
int oldPoison = poisonCounters;
|
||||
poisonCounters = num;
|
||||
view.updatePoisonCounters(this);
|
||||
int oldPoison = getCounters(CounterType.POISON);
|
||||
setCounters(CounterType.POISON, num);
|
||||
game.fireEvent(new GameEventPlayerPoisoned(this, source, oldPoison, num));
|
||||
}
|
||||
public final void addPoisonCounters(final int num, final Card source) {
|
||||
if (!hasKeyword("You can't get poison counters")) {
|
||||
setPoisonCounters(poisonCounters + num, source);
|
||||
int oldPoison = getCounters(CounterType.POISON);
|
||||
addCounter(CounterType.POISON, num, false, true);
|
||||
|
||||
if (oldPoison != getCounters(CounterType.POISON)) {
|
||||
game.fireEvent(new GameEventPlayerPoisoned(this, source, oldPoison, num));
|
||||
}
|
||||
}
|
||||
public final void removePoisonCounters(final int num, final Card source) {
|
||||
setPoisonCounters(poisonCounters - num, source);
|
||||
int oldPoison = getCounters(CounterType.POISON);
|
||||
subtractCounter(CounterType.POISON, num);
|
||||
|
||||
if (oldPoison != getCounters(CounterType.POISON)) {
|
||||
game.fireEvent(new GameEventPlayerPoisoned(this, source, oldPoison, num));
|
||||
}
|
||||
}
|
||||
// ================ POISON Merged =================================
|
||||
|
||||
public final void addChangedKeywords(final String[] addKeywords, final String[] removeKeywords, final Long timestamp) {
|
||||
addChangedKeywords(ImmutableList.copyOf(addKeywords), ImmutableList.copyOf(removeKeywords), timestamp);
|
||||
@@ -1681,7 +1794,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
|
||||
// Rule 704.5c - If a player has ten or more poison counters, he or she loses the game.
|
||||
if (poisonCounters >= 10) {
|
||||
if (getCounters(CounterType.POISON) >= 10) {
|
||||
return loseConditionMet(GameLossReason.Poisoned, null);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import forge.game.card.CounterType;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
@@ -159,6 +160,13 @@ public class PlayerView extends GameEntityView {
|
||||
set(TrackableProperty.PoisonCounters, p.getPoisonCounters());
|
||||
}
|
||||
|
||||
public Map<CounterType, Integer> getCounters() {
|
||||
return get(TrackableProperty.Counters);
|
||||
}
|
||||
void updateCounters(Player p) {
|
||||
set(TrackableProperty.Counters, p.getCounters());
|
||||
}
|
||||
|
||||
public int getMaxHandSize() {
|
||||
return get(TrackableProperty.MaxHandSize);
|
||||
}
|
||||
@@ -359,10 +367,16 @@ public class PlayerView extends GameEntityView {
|
||||
private List<String> getDetailsList() {
|
||||
final List<String> details = Lists.newArrayListWithCapacity(8);
|
||||
details.add(String.format("Life: %d", getLife()));
|
||||
final int poison = getPoisonCounters();
|
||||
if (poison > 0) {
|
||||
details.add(String.format("Poison counters: %d", poison));
|
||||
|
||||
Map<CounterType, Integer> counters = getCounters();
|
||||
if (counters != null) {
|
||||
for (Entry<CounterType, Integer> p : counters.entrySet()) {
|
||||
if (p.getValue() > 0) {
|
||||
details.add(String.format("%s counters: %d", p.getKey().getName(), p.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
details.add(String.format("Cards in hand: %d/%s", getHandSize(), getMaxHandString()));
|
||||
details.add(String.format("Cards drawn this turn: %d", getNumDrawnThisTurn()));
|
||||
details.add(String.format("Damage prevention: %d", getPreventNextDamage()));
|
||||
|
||||
@@ -12,6 +12,7 @@ public enum TrackableProperty {
|
||||
Text(TrackableTypes.StringType),
|
||||
PreventNextDamage(TrackableTypes.IntegerType),
|
||||
EnchantedBy(TrackableTypes.CardViewCollectionType),
|
||||
Counters(TrackableTypes.CounterMapType),
|
||||
|
||||
//Card
|
||||
Owner(TrackableTypes.PlayerViewType),
|
||||
@@ -27,7 +28,6 @@ public enum TrackableProperty {
|
||||
Tapped(TrackableTypes.BooleanType),
|
||||
Token(TrackableTypes.BooleanType),
|
||||
IsCommander(TrackableTypes.BooleanType),
|
||||
Counters(TrackableTypes.CounterMapType),
|
||||
Damage(TrackableTypes.IntegerType),
|
||||
AssignedDamage(TrackableTypes.IntegerType),
|
||||
ShieldCount(TrackableTypes.IntegerType),
|
||||
|
||||
12
forge-gui/res/cardsfolder/d/daxos_the_returned.txt
Normal file
12
forge-gui/res/cardsfolder/d/daxos_the_returned.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
Name:Daxos the Returned
|
||||
ManaCost:1 W B
|
||||
Types:Legendary Creature Zombie Solder
|
||||
PT:2/2
|
||||
T:Mode$ SpellCast | ValidCard$ Enchantment | ValidActivatingPlayer$ You | Execute$ TrigPutCounter | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast an enchantment spell, you get an experience counter.
|
||||
SVar:TrigPutCounter:DB$ PutCounter | Defined$ You | CounterType$ Experience | CounterNum$ 1
|
||||
A:AB$ Token | Cost$ 1 W B | TokenAmount$ 1 | TokenName$ Spirit | TokenTypes$ Creature,Spirit | TokenOwner$ You | TokenColors$ White,Black | TokenPower$ X | TokenToughness$ X | TokenImage$ W B N N Spirit | TokenStaticAbilities$ Static | TokenSVars$ X | References$ X | SpellDescription$ Put a white and black Spirit enchantment creature token onto the battlefield. It has "This creature's power and toughness are each equal to the number of experience counters you have."
|
||||
SVar:Static:Mode$ Continuous | SetPower$ X | SetToughness$ X | CharacteristicDefining$ True | Description$ This creature's power and toughness are each equal to the number of experience counters you have.
|
||||
SVar:X:Count$YourCountersExperience
|
||||
SVar:BuffedBy:Enchantment
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/daxos_the_returned.jpg
|
||||
Oracle:Whenever you cast an enchantment spell, you get an experience counter.\n{1}{W}{B}: Put a white and black Spirit enchantment creature token onto the battlefield. It has "This creature's power and toughness are each equal to the number of experience counters you have."
|
||||
@@ -14,35 +14,7 @@ import forge.game.Game;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.event.GameEvent;
|
||||
import forge.game.event.GameEventAnteCardsSelected;
|
||||
import forge.game.event.GameEventAttackersDeclared;
|
||||
import forge.game.event.GameEventBlockersDeclared;
|
||||
import forge.game.event.GameEventCardAttachment;
|
||||
import forge.game.event.GameEventCardChangeZone;
|
||||
import forge.game.event.GameEventCardCounters;
|
||||
import forge.game.event.GameEventCardDamaged;
|
||||
import forge.game.event.GameEventCardPhased;
|
||||
import forge.game.event.GameEventCardStatsChanged;
|
||||
import forge.game.event.GameEventCardTapped;
|
||||
import forge.game.event.GameEventCombatChanged;
|
||||
import forge.game.event.GameEventCombatEnded;
|
||||
import forge.game.event.GameEventGameFinished;
|
||||
import forge.game.event.GameEventGameOutcome;
|
||||
import forge.game.event.GameEventManaPool;
|
||||
import forge.game.event.GameEventPlayerControl;
|
||||
import forge.game.event.GameEventPlayerLivesChanged;
|
||||
import forge.game.event.GameEventPlayerPoisoned;
|
||||
import forge.game.event.GameEventPlayerPriority;
|
||||
import forge.game.event.GameEventPlayerStatsChanged;
|
||||
import forge.game.event.GameEventShuffle;
|
||||
import forge.game.event.GameEventSpellAbilityCast;
|
||||
import forge.game.event.GameEventSpellRemovedFromStack;
|
||||
import forge.game.event.GameEventSpellResolved;
|
||||
import forge.game.event.GameEventTurnBegan;
|
||||
import forge.game.event.GameEventTurnPhase;
|
||||
import forge.game.event.GameEventZone;
|
||||
import forge.game.event.IGameEventVisitor;
|
||||
import forge.game.event.*;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.zone.PlayerZone;
|
||||
@@ -210,6 +182,7 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
@Override
|
||||
public Void visit(final GameEventTurnBegan event) {
|
||||
turnUpdate = event.turnOwner.getView();
|
||||
processPlayer(event.turnOwner, livesUpdate);
|
||||
if (FModel.getPreferences().getPrefBoolean(FPref.UI_STACK_CREATURES) && event.turnOwner != null) {
|
||||
// anything except stack will get here
|
||||
updateZone(event.turnOwner, ZoneType.Battlefield);
|
||||
@@ -374,7 +347,9 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
final CardCollection cards = new CardCollection();
|
||||
for (final Player p : event.players) {
|
||||
cards.addAll(p.getAllCards());
|
||||
processPlayer(p, livesUpdate);
|
||||
}
|
||||
|
||||
return processCards(cards, cardsRefreshDetails);
|
||||
}
|
||||
|
||||
@@ -397,4 +372,9 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(final GameEventPlayerPoisoned event) {
|
||||
return processPlayer(event.receiver, livesUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(final GameEventPlayerCounters event) {
|
||||
return processPlayer(event.receiver, livesUpdate);
|
||||
}
|
||||
}
|
||||
@@ -31,14 +31,9 @@ public final class InputProliferate extends InputSelectManyBase<GameEntity> {
|
||||
}
|
||||
else {
|
||||
for (final Entry<GameEntity, CounterType> ge : chosenCounters.entrySet()) {
|
||||
if (ge.getKey() instanceof Player) {
|
||||
sb.append("* A poison counter to player ").append(ge.getKey()).append("\n");
|
||||
}
|
||||
else {
|
||||
sb.append("* ").append(ge.getKey()).append(" -> ").append(ge.getValue()).append("counter\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -79,7 +74,8 @@ public final class InputProliferate extends InputSelectManyBase<GameEntity> {
|
||||
|
||||
@Override
|
||||
protected final void onPlayerSelected(final Player player, final ITriggerEvent triggerEvent) {
|
||||
if (player.getPoisonCounters() == 0 || player.hasKeyword("You can't get poison counters")) {
|
||||
if (!player.hasCounters()) {
|
||||
// Can't select a player without counters
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -87,7 +83,21 @@ public final class InputProliferate extends InputSelectManyBase<GameEntity> {
|
||||
if (entityWasSelected) {
|
||||
this.chosenCounters.remove(player);
|
||||
} else {
|
||||
this.chosenCounters.put(player, null /* POISON counter is meant */);
|
||||
final List<CounterType> choices = new ArrayList<CounterType>();
|
||||
|
||||
for (final CounterType ct : player.getCounters().keySet()) {
|
||||
if (player.getCounters(ct) > 0) {
|
||||
choices.add(ct);
|
||||
}
|
||||
}
|
||||
if (player.hasKeyword("You can't get poison counters")) {
|
||||
choices.remove(CounterType.POISON);
|
||||
}
|
||||
|
||||
final CounterType toAdd = choices.size() == 1 ? choices.get(0) : getController().getGui().one("Select counter type", choices);
|
||||
chosenCounters.put(player, toAdd);
|
||||
|
||||
this.chosenCounters.put(player, CounterType.POISON);
|
||||
}
|
||||
|
||||
refresh();
|
||||
|
||||
Reference in New Issue
Block a user