mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
Fear of Sleep Paralysis and support (#6287)
This commit is contained in:
@@ -309,8 +309,10 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
|
||||
abstract public void setCounters(final Map<CounterType, Integer> allCounters);
|
||||
|
||||
abstract public boolean canRemoveCounters(final CounterType type);
|
||||
|
||||
abstract public boolean canReceiveCounters(final CounterType type);
|
||||
abstract public void subtractCounter(final CounterType counterName, final int n, final Player remover);
|
||||
abstract public int subtractCounter(final CounterType counterName, final int n, final Player remover);
|
||||
abstract public void clearCounters();
|
||||
|
||||
public boolean canReceiveCounters(final CounterEnumType type) {
|
||||
@@ -331,8 +333,8 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
addCounter(CounterType.get(counterType), n, source, table);
|
||||
}
|
||||
|
||||
public void subtractCounter(final CounterEnumType counterName, final int n, final Player remover) {
|
||||
subtractCounter(CounterType.get(counterName), n, remover);
|
||||
public int subtractCounter(final CounterEnumType counterName, final int n, final Player remover) {
|
||||
return subtractCounter(CounterType.get(counterName), n, remover);
|
||||
}
|
||||
|
||||
abstract public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params);
|
||||
|
||||
@@ -101,8 +101,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
|
||||
// uses for multi sources -> one defined/target
|
||||
// this needs given counter type
|
||||
if (sa.hasParam("ValidSource")) {
|
||||
CardCollectionView srcCards = game.getCardsIn(ZoneType.Battlefield);
|
||||
srcCards = CardLists.getValidCards(srcCards, sa.getParam("ValidSource"), activator, host, sa);
|
||||
CardCollectionView srcCards = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), sa.getParam("ValidSource"), activator, host, sa);
|
||||
List<Card> tgtCards = getDefinedCardsOrTargeted(sa);
|
||||
|
||||
if (tgtCards.isEmpty()) {
|
||||
@@ -147,11 +146,6 @@ public class CountersMoveEffect extends SpellAbilityEffect {
|
||||
Map<CounterType, Integer> countersToAdd = Maps.newHashMap();
|
||||
|
||||
for (Card src : srcCards) {
|
||||
// rule 121.5: If the first and second objects are the same object, nothing happens
|
||||
if (src.equals(dest)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ("All".equals(counterName)) {
|
||||
final Map<CounterType, Integer> tgtCounters = Maps.newHashMap(src.getCounters());
|
||||
for (Map.Entry<CounterType, Integer> e : tgtCounters.entrySet()) {
|
||||
@@ -183,8 +177,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
|
||||
params.put("CounterType", cType);
|
||||
params.put("Source", source);
|
||||
|
||||
CardCollectionView tgtCards = game.getCardsIn(ZoneType.Battlefield);
|
||||
tgtCards = CardLists.getValidCards(tgtCards, sa.getParam("ValidDefined"), activator, host, sa);
|
||||
CardCollectionView tgtCards = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), sa.getParam("ValidDefined"), activator, host, sa);
|
||||
|
||||
if (counterNum.equals("Any")) {
|
||||
tgtCards = activator.getController().chooseCardsForEffect(
|
||||
@@ -203,6 +196,9 @@ public class CountersMoveEffect extends SpellAbilityEffect {
|
||||
if (!dest.canReceiveCounters(cType)) {
|
||||
continue;
|
||||
}
|
||||
if (!source.canRemoveCounters(cType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Card cur = game.getCardState(dest, null);
|
||||
if (cur == null || !cur.equalsWithGameTimestamp(dest)) {
|
||||
@@ -287,7 +283,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
|
||||
final List<CounterType> typeChoices = Lists.newArrayList();
|
||||
// get types of counters
|
||||
for (CounterType ct : tgtCounters.keySet()) {
|
||||
if (dest.canReceiveCounters(ct)) {
|
||||
if (dest.canReceiveCounters(ct) && source.canRemoveCounters(cType)) {
|
||||
typeChoices.add(ct);
|
||||
}
|
||||
}
|
||||
@@ -337,6 +333,9 @@ public class CountersMoveEffect extends SpellAbilityEffect {
|
||||
if (!dest.canReceiveCounters(cType)) {
|
||||
return;
|
||||
}
|
||||
if (!src.canRemoveCounters(cType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int cmax = src.getCounters(cType);
|
||||
if (cmax <= 0) {
|
||||
|
||||
@@ -127,7 +127,18 @@ public class CountersPutOrRemoveEffect extends SpellAbilityEffect {
|
||||
|
||||
putCounter = !Expressions.compare(value, operator, operandValue);
|
||||
} else {
|
||||
putCounter = pc.chooseBinary(sa, prompt, BinaryChoiceType.AddOrRemove, params);
|
||||
boolean canReceive = tgtCard.canReceiveCounters(ctype);
|
||||
boolean canRemove = tgtCard.canRemoveCounters(ctype);
|
||||
if (!canReceive && !canRemove) {
|
||||
return;
|
||||
}
|
||||
if (canReceive && !canRemove) {
|
||||
putCounter = true;
|
||||
} else if (!canReceive && canRemove) {
|
||||
putCounter = false;
|
||||
} else {
|
||||
putCounter = pc.chooseBinary(sa, prompt, BinaryChoiceType.AddOrRemove, params);
|
||||
}
|
||||
}
|
||||
|
||||
if (putCounter) {
|
||||
|
||||
@@ -63,8 +63,7 @@ public class CountersRemoveAllEffect extends SpellAbilityEffect {
|
||||
for (final Card tgtCard : cards) {
|
||||
if (sa.hasParam("AllCounterTypes")) {
|
||||
for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(tgtCard.getCounters().entrySet())) {
|
||||
numberRemoved += e.getValue();
|
||||
tgtCard.subtractCounter(e.getKey(), e.getValue(), sa.getActivatingPlayer());
|
||||
numberRemoved += tgtCard.subtractCounter(e.getKey(), e.getValue(), sa.getActivatingPlayer());
|
||||
}
|
||||
//tgtCard.getCounters().clear();
|
||||
continue;
|
||||
@@ -74,7 +73,7 @@ public class CountersRemoveAllEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
if (counterAmount > 0) {
|
||||
tgtCard.subtractCounter(CounterType.getType(type), counterAmount, sa.getActivatingPlayer());
|
||||
numberRemoved += tgtCard.subtractCounter(CounterType.getType(type), counterAmount, sa.getActivatingPlayer());
|
||||
game.updateLastStateForCard(tgtCard);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,8 +110,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
|
||||
// Removing energy
|
||||
if (type.equals("All")) {
|
||||
for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(tgtPlayer.getCounters().entrySet())) {
|
||||
tgtPlayer.subtractCounter(e.getKey(), e.getValue(), activator);
|
||||
totalRemoved += e.getValue();
|
||||
totalRemoved += tgtPlayer.subtractCounter(e.getKey(), e.getValue(), activator);
|
||||
}
|
||||
} else {
|
||||
if (num.equals("All")) {
|
||||
@@ -120,8 +119,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
|
||||
if (type.equals("Any")) {
|
||||
totalRemoved += removeAnyType(tgtPlayer, cntToRemove, sa);
|
||||
} else {
|
||||
tgtPlayer.subtractCounter(counterType, cntToRemove, activator);
|
||||
totalRemoved += cntToRemove;
|
||||
totalRemoved += tgtPlayer.subtractCounter(counterType, cntToRemove, activator);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -165,11 +163,11 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
|
||||
if (gameCard == null || !tgtCard.equalsWithGameTimestamp(gameCard)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Zone zone = game.getZoneOf(gameCard);
|
||||
if (type.equals("All")) {
|
||||
for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(gameCard.getCounters().entrySet())) {
|
||||
gameCard.subtractCounter(e.getKey(), e.getValue(), activator);
|
||||
totalRemoved += e.getValue();
|
||||
totalRemoved += gameCard.subtractCounter(e.getKey(), e.getValue(), activator);
|
||||
}
|
||||
game.updateLastStateForCard(gameCard);
|
||||
continue;
|
||||
@@ -180,6 +178,9 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
|
||||
if (type.equals("Any")) {
|
||||
totalRemoved += removeAnyType(gameCard, cntToRemove, sa);
|
||||
} else {
|
||||
if (!tgtCard.canRemoveCounters(counterType)) {
|
||||
continue;
|
||||
}
|
||||
cntToRemove = Math.min(cntToRemove, gameCard.getCounters(counterType));
|
||||
|
||||
if (zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Exile)) {
|
||||
@@ -221,14 +222,18 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
final PlayerController pc = activator.getController();
|
||||
final Map<CounterType, Integer> tgtCounters = Maps.newHashMap(entity.getCounters());
|
||||
for (CounterType ct : ImmutableList.copyOf(tgtCounters.keySet())) {
|
||||
if (!entity.canRemoveCounters(ct)) {
|
||||
tgtCounters.remove(ct);
|
||||
}
|
||||
}
|
||||
|
||||
while (cntToRemove > 0 && !tgtCounters.isEmpty()) {
|
||||
Map<String, Object> params = Maps.newHashMap();
|
||||
params.put("Target", entity);
|
||||
|
||||
String prompt = Localizer.getInstance().getMessage("lblSelectCountersTypeToRemove");
|
||||
CounterType chosenType = pc.chooseCounterType(
|
||||
ImmutableList.copyOf(tgtCounters.keySet()), sa, prompt, params);
|
||||
CounterType chosenType = pc.chooseCounterType(ImmutableList.copyOf(tgtCounters.keySet()), sa, prompt, params);
|
||||
|
||||
int max = Math.min(cntToRemove, tgtCounters.get(chosenType));
|
||||
// remove selection so player can't cheat additional trigger by choosing the same type multiple times
|
||||
|
||||
@@ -1600,6 +1600,21 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean canRemoveCounters(final CounterType type) {
|
||||
if (isPhasedOut()) {
|
||||
return false;
|
||||
}
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
||||
repParams.put(AbilityKey.CounterType, type);
|
||||
repParams.put(AbilityKey.Result, 0);
|
||||
repParams.put(AbilityKey.IsDamage, false);
|
||||
if (game.getReplacementHandler().cantHappenCheck(ReplacementType.RemoveCounter, repParams)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) {
|
||||
int addAmount = n;
|
||||
@@ -1736,11 +1751,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void subtractCounter(final CounterType counterName, final int n, final Player remover) {
|
||||
subtractCounter(counterName, n, remover, false);
|
||||
public final int subtractCounter(final CounterType counterName, final int n, final Player remover) {
|
||||
return subtractCounter(counterName, n, remover, false);
|
||||
}
|
||||
|
||||
public final void subtractCounter(final CounterType counterName, final int n, final Player remover, final boolean isDamage) {
|
||||
public final int subtractCounter(final CounterType counterName, final int n, final Player remover, final boolean isDamage) {
|
||||
int oldValue = getCounters(counterName);
|
||||
int newValue = Math.max(oldValue - n, 0);
|
||||
|
||||
@@ -1758,12 +1773,14 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
newValue = 0;
|
||||
}
|
||||
break;
|
||||
case Replaced:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
final int delta = oldValue - newValue;
|
||||
if (delta == 0) { return; }
|
||||
if (delta == 0) { return 0; }
|
||||
|
||||
int powerBonusBefore = getPowerBonusFromCounters();
|
||||
int toughnessBonusBefore = getToughnessBonusFromCounters();
|
||||
@@ -1800,6 +1817,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
runParams.put(AbilityKey.CounterAmount, delta);
|
||||
runParams.put(AbilityKey.NewCounterAmount, newValue);
|
||||
getGame().getTriggerHandler().runTrigger(TriggerType.CounterRemovedOnce, runParams, false);
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -70,10 +70,16 @@ public class CostRemoveAnyCounter extends CostPart {
|
||||
int allCounters = 0;
|
||||
for (Card c : validCards) {
|
||||
if (this.counter != null) {
|
||||
if (!c.canRemoveCounters(this.counter)) {
|
||||
continue;
|
||||
}
|
||||
allCounters += c.getCounters(this.counter);
|
||||
} else {
|
||||
for (Integer value : c.getCounters().values()) {
|
||||
allCounters += value;
|
||||
for (Map.Entry<CounterType, Integer> entry : c.getCounters().entrySet()) {
|
||||
if (!c.canRemoveCounters(entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
allCounters += entry.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ import com.google.common.collect.Maps;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.trigger.TriggerType;
|
||||
@@ -78,7 +80,8 @@ public class CostUntap extends CostPart {
|
||||
@Override
|
||||
public final boolean canPay(final SpellAbility ability, final Player payer, final boolean effect) {
|
||||
final Card source = ability.getHostCard();
|
||||
return source.isTapped() && !source.isAbilitySick();
|
||||
return source.isTapped() && !source.isAbilitySick() &&
|
||||
(source.getCounters(CounterEnumType.STUN) == 0 || source.canRemoveCounters(CounterType.get(CounterEnumType.STUN)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,6 +23,8 @@ import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.card.CardPredicates.Presets;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
@@ -90,7 +92,7 @@ public class CostUntapType extends CostPartWithList {
|
||||
if (!canUntapSource) {
|
||||
typeList.remove(source);
|
||||
}
|
||||
typeList = CardLists.filter(typeList, Presets.TAPPED);
|
||||
typeList = CardLists.filter(typeList, Presets.TAPPED, c -> c.getCounters(CounterEnumType.STUN) == 0 || c.canRemoveCounters(CounterType.get(CounterEnumType.STUN)));
|
||||
|
||||
final int amount = this.getAbilityAmount(ability);
|
||||
return (typeList.size() != 0) && (typeList.size() >= amount);
|
||||
|
||||
@@ -855,6 +855,14 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return true;
|
||||
}
|
||||
|
||||
public final boolean canRemoveCounters(final CounterType type) {
|
||||
if (!isInGame()) {
|
||||
return false;
|
||||
}
|
||||
// no RE affecting players currently, skip check for performance
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) {
|
||||
int addAmount = n;
|
||||
@@ -896,12 +904,12 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subtractCounter(CounterType counterName, int num, final Player remover) {
|
||||
public int subtractCounter(CounterType counterName, int num, final Player remover) {
|
||||
int oldValue = getCounters(counterName);
|
||||
int newValue = Math.max(oldValue - num, 0);
|
||||
|
||||
final int delta = oldValue - newValue;
|
||||
if (delta == 0) { return; }
|
||||
if (delta == 0) { return 0; }
|
||||
|
||||
setCounters(counterName, newValue, null, true);
|
||||
|
||||
@@ -917,6 +925,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
getGame().getTriggerHandler().runTrigger(TriggerType.CounterRemoved, runParams, false);
|
||||
}
|
||||
*/
|
||||
return delta;
|
||||
}
|
||||
|
||||
public final void clearCounters() {
|
||||
|
||||
Reference in New Issue
Block a user