Fear of Sleep Paralysis and support (#6287)

This commit is contained in:
tool4ever
2024-10-14 12:55:00 +02:00
committed by GitHub
parent 8f33da5b9c
commit b6f118f89b
15 changed files with 110 additions and 48 deletions

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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();
}
}
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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() {