mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
Merge pull request #2626 from tool4ever/fixnpe6
Fix Churning Reservoir NPE
This commit is contained in:
@@ -358,7 +358,7 @@ public class DamageDealAi extends DamageAiBase {
|
|||||||
return c.getSVar("Targeting").equals("Dies")
|
return c.getSVar("Targeting").equals("Dies")
|
||||||
|| (ComputerUtilCombat.getEnoughDamageToKill(c, d, source, false, noPrevention) <= d)
|
|| (ComputerUtilCombat.getEnoughDamageToKill(c, d, source, false, noPrevention) <= d)
|
||||||
&& !ComputerUtil.canRegenerate(ai, c)
|
&& !ComputerUtil.canRegenerate(ai, c)
|
||||||
&& !(c.getSVar("SacMe").length() > 0)
|
&& !c.hasSVar("SacMe")
|
||||||
&& !ComputerUtilCard.hasActiveUndyingOrPersist(c);
|
&& !ComputerUtilCard.hasActiveUndyingOrPersist(c);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -437,7 +437,7 @@ public class DamageDealAi extends DamageAiBase {
|
|||||||
return c.getSVar("Targeting").equals("Dies")
|
return c.getSVar("Targeting").equals("Dies")
|
||||||
|| (ComputerUtilCombat.getEnoughDamageToKill(c, d, source, false, noPrevention) <= d)
|
|| (ComputerUtilCombat.getEnoughDamageToKill(c, d, source, false, noPrevention) <= d)
|
||||||
&& !ComputerUtil.canRegenerate(ai, c)
|
&& !ComputerUtil.canRegenerate(ai, c)
|
||||||
&& !(c.getSVar("SacMe").length() > 0);
|
&& !c.hasSVar("SacMe");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1460,20 +1460,6 @@ public class AbilityUtils {
|
|||||||
if (unlessCost.equals("CardManaCost")) {
|
if (unlessCost.equals("CardManaCost")) {
|
||||||
cost = new Cost(source.getManaCost(), true);
|
cost = new Cost(source.getManaCost(), true);
|
||||||
}
|
}
|
||||||
else if (unlessCost.equals("TriggeredSpellManaCost")) {
|
|
||||||
SpellAbility triggered = (SpellAbility) sa.getRootAbility().getTriggeringObject(AbilityKey.SpellAbility);
|
|
||||||
Card triggeredCard = triggered.getHostCard();
|
|
||||||
if (triggeredCard.getManaCost() == null) {
|
|
||||||
cost = new Cost(ManaCost.ZERO, true);
|
|
||||||
} else {
|
|
||||||
int xCount = triggeredCard.getManaCost().countX();
|
|
||||||
int xPaid = triggeredCard.getXManaCostPaid() * xCount;
|
|
||||||
ManaCostBeingPaid toPay = new ManaCostBeingPaid(triggeredCard.getManaCost());
|
|
||||||
toPay.decreaseShard(ManaCostShard.X, xCount);
|
|
||||||
toPay.increaseGenericMana(xPaid);
|
|
||||||
cost = new Cost(toPay.toManaCost(), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (unlessCost.equals("ChosenManaCost")) {
|
else if (unlessCost.equals("ChosenManaCost")) {
|
||||||
if (!source.hasChosenCard()) {
|
if (!source.hasChosenCard()) {
|
||||||
cost = new Cost(ManaCost.ZERO, true);
|
cost = new Cost(ManaCost.ZERO, true);
|
||||||
@@ -2734,7 +2720,7 @@ public class AbilityUtils {
|
|||||||
|
|
||||||
// Count$ThisTurnEntered <ZoneDestination> [from <ZoneOrigin>] <Valid>
|
// Count$ThisTurnEntered <ZoneDestination> [from <ZoneOrigin>] <Valid>
|
||||||
if (sq[0].startsWith("ThisTurnEntered")) {
|
if (sq[0].startsWith("ThisTurnEntered")) {
|
||||||
final String[] workingCopy = l[0].split("_");
|
final String[] workingCopy = l[0].split("_", 5);
|
||||||
|
|
||||||
ZoneType destination = ZoneType.smartValueOf(workingCopy[1]);
|
ZoneType destination = ZoneType.smartValueOf(workingCopy[1]);
|
||||||
final boolean hasFrom = workingCopy[2].equals("from");
|
final boolean hasFrom = workingCopy[2].equals("from");
|
||||||
@@ -2747,7 +2733,7 @@ public class AbilityUtils {
|
|||||||
|
|
||||||
// Count$LastTurnEntered <ZoneDestination> [from <ZoneOrigin>] <Valid>
|
// Count$LastTurnEntered <ZoneDestination> [from <ZoneOrigin>] <Valid>
|
||||||
if (sq[0].startsWith("LastTurnEntered")) {
|
if (sq[0].startsWith("LastTurnEntered")) {
|
||||||
final String[] workingCopy = l[0].split("_");
|
final String[] workingCopy = l[0].split("_", 5);
|
||||||
|
|
||||||
ZoneType destination = ZoneType.smartValueOf(workingCopy[1]);
|
ZoneType destination = ZoneType.smartValueOf(workingCopy[1]);
|
||||||
final boolean hasFrom = workingCopy[2].equals("from");
|
final boolean hasFrom = workingCopy[2].equals("from");
|
||||||
|
|||||||
@@ -905,7 +905,7 @@ public abstract class SpellAbilityEffect {
|
|||||||
return activator.getController().chooseSingleEntityForEffect(options, sa, Localizer.getInstance().getMessage("lblChoosePlayer"), null);
|
return activator.getController().chooseSingleEntityForEffect(options, sa, Localizer.getInstance().getMessage("lblChoosePlayer"), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleExiledWith(final Card movedCard, final SpellAbility cause) {
|
public static void handleExiledWith(final Card movedCard, final SpellAbility cause) {
|
||||||
Card exilingSource = cause.getHostCard();
|
Card exilingSource = cause.getHostCard();
|
||||||
// during replacement LKI might be used
|
// during replacement LKI might be used
|
||||||
if (cause.isReplacementAbility() && exilingSource.isLKI()) {
|
if (cause.isReplacementAbility() && exilingSource.isLKI()) {
|
||||||
|
|||||||
@@ -1501,32 +1501,13 @@ public class CardProperty {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// syntax example: countersGE9 P1P1 or countersLT12TIME (greater number
|
|
||||||
// than 99 not supported)
|
|
||||||
/*
|
|
||||||
* slapshot5 - fair warning, you cannot use numbers with 2 digits
|
|
||||||
* (greater number than 9 not supported you can use X and the
|
|
||||||
* SVar:X:Number$12 to get two digits. This will need a better fix, and
|
|
||||||
* I have the beginnings of a regex below
|
|
||||||
*/
|
|
||||||
else if (property.startsWith("counters")) {
|
else if (property.startsWith("counters")) {
|
||||||
/*
|
// syntax example: counters_GE9_P1P1 or counters_LT12_TIME
|
||||||
* Pattern p = Pattern.compile("[a-z]*[A-Z][A-Z][X0-9]+.*$");
|
|
||||||
* String[] parse = ???
|
|
||||||
* System.out.println("Parsing completed of: "+Property); for (int i
|
|
||||||
* = 0; i < parse.length; i++) {
|
|
||||||
* System.out.println("parse["+i+"]: "+parse[i]); }
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO get a working regex out of this pattern so the amount of
|
|
||||||
// digits doesn't matter
|
|
||||||
final String[] splitProperty = property.split("_");
|
final String[] splitProperty = property.split("_");
|
||||||
final String strNum = splitProperty[1].substring(2);
|
final String strNum = splitProperty[1].substring(2);
|
||||||
final String comparator = splitProperty[1].substring(0, 2);
|
final String comparator = splitProperty[1].substring(0, 2);
|
||||||
String counterType;
|
final String counterType = splitProperty[2];
|
||||||
int number = AbilityUtils.calculateAmount(source, strNum, spellAbility);
|
final int number = AbilityUtils.calculateAmount(source, strNum, spellAbility);
|
||||||
counterType = splitProperty[2];
|
|
||||||
|
|
||||||
final int actualnumber = card.getCounters(CounterType.getType(counterType));
|
final int actualnumber = card.getCounters(CounterType.getType(counterType));
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package forge.game.cost;
|
|||||||
|
|
||||||
import forge.card.CardType;
|
import forge.card.CardType;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
import forge.game.card.CardLists;
|
import forge.game.card.CardLists;
|
||||||
@@ -187,11 +188,8 @@ public class CostExile extends CostPartWithList {
|
|||||||
@Override
|
@Override
|
||||||
protected Card doPayment(SpellAbility ability, Card targetCard, final boolean effect) {
|
protected Card doPayment(SpellAbility ability, Card targetCard, final boolean effect) {
|
||||||
final Game game = targetCard.getGame();
|
final Game game = targetCard.getGame();
|
||||||
final Card host = ability.getHostCard();
|
|
||||||
Card newCard = game.getAction().exile(targetCard, null);
|
Card newCard = game.getAction().exile(targetCard, null);
|
||||||
host.addExiledCard(newCard);
|
SpellAbilityEffect.handleExiledWith(newCard, ability);
|
||||||
newCard.setExiledWith(host);
|
|
||||||
newCard.setExiledBy(ability.getActivatingPlayer());
|
|
||||||
return newCard;
|
return newCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,21 +70,11 @@ public class CostUnattach extends CostPartWithList {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final boolean canPay(final SpellAbility ability, final Player payer, final boolean effect) {
|
public final boolean canPay(final SpellAbility ability, final Player payer, final boolean effect) {
|
||||||
final Card source = ability.getHostCard();
|
return findCardToUnattach(ability.getHostCard(), payer, ability) != null;
|
||||||
|
|
||||||
final String type = this.getType();
|
|
||||||
if (type.equals("CARDNAME")) {
|
|
||||||
return source.isEquipping();
|
|
||||||
} else if (type.equals("OriginalHost")) {
|
|
||||||
Card originalEquipment = ability.getOriginalHost();
|
|
||||||
return originalEquipment.isEquipping();
|
|
||||||
} else {
|
|
||||||
return CardLists.getValidCards(source.getEquippedBy(), type, payer, source, ability).size() > 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Card findCardToUnattach(final Card source, Player activator, SpellAbility ability) {
|
public Card findCardToUnattach(final Card source, Player activator, SpellAbility ability) {
|
||||||
if (getType().equals("CARDNAME")) {
|
if (payCostFromSource()) {
|
||||||
if (source.isEquipping()) {
|
if (source.isEquipping()) {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -503,8 +503,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
|
|
||||||
if (thisHasFizzled) { // Fizzle
|
if (thisHasFizzled) { // Fizzle
|
||||||
if (sa.isBestow()) {
|
if (sa.isBestow()) {
|
||||||
// 702.102d: if its target is illegal,
|
// 702.102e: if its target is illegal, the effect making it an Aura spell ends.
|
||||||
// the effect making it an Aura spell ends.
|
|
||||||
// It continues resolving as a creature spell.
|
// It continues resolving as a creature spell.
|
||||||
source.unanimateBestow();
|
source.unanimateBestow();
|
||||||
SpellAbility first = source.getFirstSpellAbility();
|
SpellAbility first = source.getFirstSpellAbility();
|
||||||
@@ -834,10 +833,9 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (activator.equals(activePlayer)) {
|
if (activator.equals(activePlayer)) {
|
||||||
|
adjustAuraHost(sa);
|
||||||
activePlayerSAs.add(sa);
|
activePlayerSAs.add(sa);
|
||||||
}
|
}
|
||||||
|
|
||||||
adjustAuraHost(sa);
|
|
||||||
}
|
}
|
||||||
simultaneousStackEntryList.removeAll(activePlayerSAs);
|
simultaneousStackEntryList.removeAll(activePlayerSAs);
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,8 @@ PT:3/2
|
|||||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.YouCtrl+Other,Artifact.YouCtrl+Other | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever another creature or artifact you control is put into a graveyard from the battlefield, put an oil counter on CARDNAME.
|
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.YouCtrl+Other,Artifact.YouCtrl+Other | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever another creature or artifact you control is put into a graveyard from the battlefield, put an oil counter on CARDNAME.
|
||||||
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ OIL | CounterNum$ 1
|
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ OIL | CounterNum$ 1
|
||||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigImmediateTrig | TriggerDescription$ Whenever CARDNAME attacks, you may remove two oil counters from it. When you do, target creature can't block this turn.
|
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigImmediateTrig | TriggerDescription$ Whenever CARDNAME attacks, you may remove two oil counters from it. When you do, target creature can't block this turn.
|
||||||
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ SubCounter<2/OIL> | SubAbility$ TrigPump | TriggerDescription$ When you do, target creature can't block this turn.
|
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ SubCounter<2/OIL> | Execute$ TrigPump | TriggerDescription$ When you do, target creature can't block this turn.
|
||||||
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | IsCurse$ True | KW$ HIDDEN CARDNAME can't block.
|
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | IsCurse$ True | KW$ HIDDEN CARDNAME can't block.
|
||||||
SVar:X:Count$CardCounters.OIL
|
|
||||||
SVar:HasAttackEffect:TRUE
|
SVar:HasAttackEffect:TRUE
|
||||||
DeckHints:Ability$Counters
|
DeckHints:Ability$Counters
|
||||||
Oracle:Whenever another creature or artifact you control is put into a graveyard from the battlefield, put an oil counter on Forgehammer Centurion.\nWhenever Forgehammer Centurion attacks, you may remove two oil counters from it. When you do, target creature can't block this turn.
|
Oracle:Whenever another creature or artifact you control is put into a graveyard from the battlefield, put an oil counter on Forgehammer Centurion.\nWhenever Forgehammer Centurion attacks, you may remove two oil counters from it. When you do, target creature can't block this turn.
|
||||||
|
|||||||
@@ -379,8 +379,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
|||||||
private PaymentDecision exileFromMiscZone(final CostExile cost, final SpellAbility sa, final int nNeeded, final CardCollection typeList) {
|
private PaymentDecision exileFromMiscZone(final CostExile cost, final SpellAbility sa, final int nNeeded, final CardCollection typeList) {
|
||||||
if (typeList.size() < nNeeded) { return null; }
|
if (typeList.size() < nNeeded) { return null; }
|
||||||
|
|
||||||
final List<ZoneType> origin = Lists.newArrayList();
|
final List<ZoneType> origin = Lists.newArrayList(cost.from);
|
||||||
origin.add(cost.from);
|
|
||||||
final CardCollection exiled = new CardCollection();
|
final CardCollection exiled = new CardCollection();
|
||||||
|
|
||||||
final List<Card> chosen = controller.chooseCardsForZoneChange(ZoneType.Exile, origin, sa, typeList, mandatory ? nNeeded : 0,
|
final List<Card> chosen = controller.chooseCardsForZoneChange(ZoneType.Exile, origin, sa, typeList, mandatory ? nNeeded : 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user