Some fixes (#6004)

* Fix NPE
This commit is contained in:
tool4ever
2024-08-28 17:54:28 +02:00
committed by GitHub
parent 4b533d22a0
commit 756ba28a14
21 changed files with 51 additions and 94 deletions

View File

@@ -66,11 +66,7 @@ public class GameCopier {
}
public Game makeCopy() {
if (origGame.EXPERIMENTAL_RESTORE_SNAPSHOT) {
return snapshot.makeCopy();
} else {
return makeCopy(null, null);
}
return makeCopy(null, null);
}
public Game makeCopy(PhaseType advanceToPhase, Player aiPlayer) {
if (origGame.EXPERIMENTAL_RESTORE_SNAPSHOT) {

View File

@@ -138,11 +138,6 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
return unFoiledVersion;
}
// @Override
// public String getImageKey() {
// return getImageLocator(getImageName(), getArtIndex(), true, false);
// }
@Override
public String getItemType() {
final Localizer localizer = Localizer.getInstance();

View File

@@ -27,6 +27,7 @@ import forge.game.spellability.SpellAbility;
import forge.game.trigger.Trigger;
import forge.game.zone.ZoneType;
import forge.util.Expressions;
import forge.util.ITranslatable;
/**
* Base class for Triggers,ReplacementEffects and StaticAbilities.
@@ -623,6 +624,14 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
return getCardState().getView().getState();
}
public ITranslatable getHostName(CardTraitBase node) {
// if alternate state is viewed while card uses original
if (node.isIntrinsic() && node.cardState != null && !node.cardState.getStateName().equals(getHostCard().getCurrentStateName())) {
return node.cardState;
}
return node.getHostCard();
}
public Card getOriginalHost() {
if (getCardState() != null)
return getCardState().getCard();

View File

@@ -1507,6 +1507,7 @@ public class GameAction {
if (!c.isSaga()) {
return false;
}
// needs to be effect, because otherwise it might be a cost?
if (!c.canBeSacrificedBy(null, true)) {
return false;
}
@@ -1514,7 +1515,6 @@ public class GameAction {
return false;
}
if (!game.getStack().hasSourceOnStack(c, SpellAbilityPredicates.isChapter())) {
// needs to be effect, because otherwise it might be a cost?
sacrificeList.add(c);
checkAgain = true;
}
@@ -1537,6 +1537,7 @@ public class GameAction {
}
return checkAgain;
}
private boolean stateBasedAction_Role(Card c, CardCollection removeList) {
if (!c.hasCardAttachments()) {
return false;
@@ -1552,7 +1553,6 @@ public class GameAction {
if (rolesByPlayer.size() <= 1) {
continue;
}
// sort by game timestamp
rolesByPlayer.sort(CardPredicates.compareByGameTimestamp());
removeList.addAll(rolesByPlayer.subList(0, rolesByPlayer.size() - 1));
checkAgain = true;
@@ -1780,7 +1780,6 @@ public class GameAction {
}
private boolean handlePlaneswalkerRule(Player p, CardCollection noRegCreats) {
// get all Planeswalkers
final List<Card> list = p.getPlaneswalkersInPlay();
boolean recheck = false;
@@ -2584,7 +2583,6 @@ public class GameAction {
player.addCompletedDungeon(dungeon);
ceaseToExist(dungeon, true);
// Run RoomEntered trigger
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(dungeon);
runParams.put(AbilityKey.Player, player);
game.getTriggerHandler().runTrigger(TriggerType.DungeonCompleted, runParams, false);

View File

@@ -30,16 +30,7 @@ public class AbilityApiBased extends AbilityActivated {
@Override
public String getStackDescription() {
StringBuilder sb = new StringBuilder();
if (this.hostCard.hasPromisedGift() && this.isSpell() && !this.hostCard.isPermanent()) {
sb.append("Gift a ").
append(this.getAdditionalAbility("GiftAbility").getParam("GiftDescription")).
append(" to ").append(this.hostCard.getPromisedGift()).
append(". ");
}
sb.append(effect.getStackDescriptionWithSubs(mapParams, this));
return sb.toString();
return effect.getStackDescriptionWithSubs(mapParams, this);
}
/* (non-Javadoc)

View File

@@ -64,6 +64,11 @@ public abstract class SpellAbilityEffect {
// prelude for when this is root ability
if (!(sa instanceof AbilitySub)) {
sb.append(sa.getHostCard()).append(" -");
if (sa.getHostCard().hasPromisedGift()) {
sb.append(" Gift ").
append(sa.getAdditionalAbility("GiftAbility").getParam("GiftDescription")).
append(" to ").append(sa.getHostCard().getPromisedGift()).append(". ");
}
}
sb.append(" ");
}
@@ -462,6 +467,7 @@ public abstract class SpellAbilityEffect {
public static void addForgetOnMovedTrigger(final Card card, final String zone) {
String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ " + zone + " | ExcludedDestinations$ Stack,Exile | Destination$ Any | TriggerZones$ Command | Static$ True";
// CR 400.8 Exiled card becomes new object when it's exiled
String trig2 = "Mode$ Exiled | ValidCard$ Card.IsRemembered | ValidCause$ SpellAbility.!EffectSource | TriggerZones$ Command | Static$ True";
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, card, true);

View File

@@ -28,7 +28,6 @@ public class AnimateAllEffect extends AnimateEffectBase {
public void resolve(final SpellAbility sa) {
final Card host = sa.getHostCard();
// AF specific sa
Integer power = null;
if (sa.hasParam("Power")) {
power = AbilityUtils.calculateAmount(host, sa.getParam("Power"), sa);

View File

@@ -208,7 +208,7 @@ public class CopyPermanentEffect extends TokenEffectBase {
Player chooser = activator;
if (sa.hasParam("Chooser")) {
final String choose = sa.getParam("Chooser");
chooser = AbilityUtils.getDefinedPlayers(sa.getHostCard(), choose, sa).get(0);
chooser = AbilityUtils.getDefinedPlayers(host, choose, sa).get(0);
}
// For Mimic Vat with mutated creature, need to choose one imprinted card
@@ -272,7 +272,6 @@ public class CopyPermanentEffect extends TokenEffectBase {
if (!useZoneTable) {
triggerList.triggerChangesZoneAll(game, sa);
triggerList.clear();
}
if (combatChanged.isTrue()) {
game.updateCombatForView();

View File

@@ -56,8 +56,7 @@ public class DamageAllEffect extends DamageBaseEffect {
final Card sourceLKI = card.getGame().getChangeZoneLKIInfo(card);
final Game game = sa.getActivatingPlayer().getGame();
final String damage = sa.getParam("NumDmg");
final int dmg = AbilityUtils.calculateAmount(source, damage, sa);
final int dmg = AbilityUtils.calculateAmount(source, sa.getParam("NumDmg"), sa);
//Remember params from this effect have been moved to dealDamage in GameAction
Player targetPlayer = sa.getTargets().getFirstTargetedPlayer();

View File

@@ -43,7 +43,7 @@ public class MakeCardEffect extends SpellAbilityEffect {
List<ICardFace> faces = new ArrayList<>();
List<PaperCard> pack = null;
List<String> names = Lists.newArrayList();
final String desc = sa.getParamOrDefault("OptionPrompt", "");
if (sa.hasParam("Optional") && sa.hasParam("OptionPrompt") && //for now, OptionPrompt is needed
!player.getController().confirmAction(sa, null, Localizer.getInstance().getMessage(desc), null)) {
@@ -175,7 +175,7 @@ public class MakeCardEffect extends SpellAbilityEffect {
CardCollection madeCards = new CardCollection();
final boolean wCounter = sa.hasParam("WithCounter");
final boolean battlefield = zone.equals(ZoneType.Battlefield);
for (final Card c : cards) {
if (wCounter && battlefield) {
int numCtr = AbilityUtils.calculateAmount(source, sa.getParamOrDefault("WithCounterNum", "1"), sa);
@@ -230,7 +230,7 @@ public class MakeCardEffect extends SpellAbilityEffect {
}
}
private List<ICardFace> parseFaces (final SpellAbility sa, final String param) {
private List<ICardFace> parseFaces(final SpellAbility sa, final String param) {
List<ICardFace> parsedFaces = new ArrayList<>();
for (String s : sa.getParam(param).split(",")) {
// Cardnames that include "," must use ";" instead (i.e. Tovolar; Dire Overlord)
@@ -244,7 +244,7 @@ public class MakeCardEffect extends SpellAbilityEffect {
return parsedFaces;
}
private Card finishMaking (final SpellAbility sa, final Card made, final Card source) {
private Card finishMaking(final SpellAbility sa, final Card made, final Card source) {
if (sa.hasParam("FaceDown")) made.turnFaceDown(true);
if (sa.hasParam("RememberMade")) source.addRemembered(made);
if (sa.hasParam("ImprintMade")) source.addImprintedCard(made);

View File

@@ -11,14 +11,12 @@ public class GameEventSpellAbilityCast extends GameEvent {
public final SpellAbility sa;
public final SpellAbilityStackInstance si;
public final boolean replicate;
public final int stackIndex;
public GameEventSpellAbilityCast(SpellAbility sp, SpellAbilityStackInstance si, int stackIndex, boolean replicate) {
public GameEventSpellAbilityCast(SpellAbility sp, SpellAbilityStackInstance si, int stackIndex) {
sa = sp;
this.si = si;
this.stackIndex = stackIndex;
this.replicate = replicate;
}
/* (non-Javadoc)

View File

@@ -2017,14 +2017,7 @@ public class Player extends GameEntity implements Comparable<Player> {
}
public final boolean cantWin() {
boolean isAnyOppLoseProof = false;
for (Player p : game.getPlayers()) {
if (p == this || p.getOutcome() != null) {
continue; // except self and already dead
}
isAnyOppLoseProof |= p.hasKeyword("You can't lose the game.");
}
return hasKeyword("You can't win the game.") || isAnyOppLoseProof;
return hasKeyword("You can't win the game.");
}
public final boolean checkLoseCondition() {

View File

@@ -10,7 +10,6 @@ import forge.game.GameType;
import forge.item.IPaperCard;
import forge.item.PaperCard;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -19,10 +18,10 @@ public class RegisteredPlayer {
private final Deck originalDeck; // never return or modify this instance (it's a reference to game resources)
private Deck currentDeck;
private static final Iterable<PaperCard> EmptyList = Collections.unmodifiableList(new ArrayList<>());
private static final Iterable<PaperCard> EmptyList = Collections.emptyList();
private LobbyPlayer player = null;
private int startingLife = 20;
private int startingHand = 7;
private int manaShards = 0;
@@ -40,7 +39,7 @@ public class RegisteredPlayer {
private Integer id = null;
private boolean randomFoil = false;
private boolean enableETBCountersEffect = false;
public RegisteredPlayer(Deck deck0) {
originalDeck = deck0;
restoreDeck();
@@ -49,7 +48,6 @@ public class RegisteredPlayer {
public final Integer getId() {
return id;
}
public final void setId(Integer id0) {
id = id0;
}
@@ -57,19 +55,10 @@ public class RegisteredPlayer {
public final Deck getDeck() {
return currentDeck;
}
public final int getStartingLife() {
return startingLife;
}
public final Iterable<? extends IPaperCard> getCardsOnBattlefield() {
return Iterables.concat(cardsOnBattlefield == null ? EmptyList : cardsOnBattlefield,
extraCardsOnBattlefield == null ? EmptyList : extraCardsOnBattlefield);
}
public final Iterable<? extends IPaperCard> getExtraCardsInCommandZone() {
return extraCardsInCommandZone == null ? EmptyList : extraCardsInCommandZone;
}
public final void setStartingLife(int startingLife) {
this.startingLife = startingLife;
}
@@ -77,7 +66,6 @@ public class RegisteredPlayer {
public final int getManaShards() {
return manaShards;
}
public final void setManaShards(int manaShards) {
this.manaShards = manaShards;
}
@@ -89,6 +77,15 @@ public class RegisteredPlayer {
enableETBCountersEffect = value;
}
public final Iterable<? extends IPaperCard> getCardsOnBattlefield() {
return Iterables.concat(cardsOnBattlefield == null ? EmptyList : cardsOnBattlefield,
extraCardsOnBattlefield == null ? EmptyList : extraCardsOnBattlefield);
}
public final Iterable<? extends IPaperCard> getExtraCardsInCommandZone() {
return extraCardsInCommandZone == null ? EmptyList : extraCardsInCommandZone;
}
public final void setCardsOnBattlefield(Iterable<IPaperCard> cardsOnTable) {
this.cardsOnBattlefield = cardsOnTable;
}
@@ -137,7 +134,6 @@ public class RegisteredPlayer {
public int getTeamNumber() {
return teamNumber;
}
public void setTeamNumber(int teamNumber0) {
this.teamNumber = teamNumber0;
}
@@ -153,7 +149,7 @@ public class RegisteredPlayer {
final Set<GameType> appliedVariants, final Deck deck, //General vars
final Iterable<PaperCard> schemes, final boolean playerIsArchenemy, //Archenemy specific vars
final Iterable<PaperCard> planes, final CardPool vanguardAvatar) { //Planechase and Vanguard
RegisteredPlayer start = new RegisteredPlayer(deck);
if (appliedVariants.contains(GameType.Archenemy) && playerIsArchenemy) {
start.setStartingLife(40); // 904.5: The Archenemy has 40 life.
@@ -192,7 +188,6 @@ public class RegisteredPlayer {
public LobbyPlayer getPlayer() {
return player;
}
public RegisteredPlayer setPlayer(LobbyPlayer player0) {
this.player = player0;
return this;
@@ -219,7 +214,6 @@ public class RegisteredPlayer {
setStartingLife(getStartingLife() + avatar.getRules().getLife());
setStartingHand(getStartingHand() + avatar.getRules().getHand());
}
}
public PaperCard getPlaneswalker() {

View File

@@ -110,7 +110,6 @@ public class ReplaceAddCounter extends ReplacementEffect {
@Override
public boolean modeCheck(ReplacementType event, Map<AbilityKey, Object> runParams) {
// TODO Auto-generated method stub
if (super.modeCheck(event, runParams)) {
return true;
}

View File

@@ -222,12 +222,7 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
public String getDescription() {
if (hasParam("Description") && !this.isSuppressed()) {
String desc = AbilityUtils.applyDescriptionTextChangeEffects(getParam("Description"), this);
ITranslatable nameSource;
if (this.isIntrinsic() && cardState != null && cardState.getCard() == getHostCard()) {
nameSource = cardState;
} else {
nameSource = getHostCard();
}
ITranslatable nameSource = getHostName(this);
desc = CardTranslation.translateMultipleDescriptionText(desc, nameSource);
String translatedName = CardTranslation.getTranslatedName(nameSource);
desc = TextUtil.fastReplace(desc, "CARDNAME", translatedName);

View File

@@ -984,13 +984,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
}
String desc = node.getDescription();
if (node.getHostCard() != null) {
ITranslatable nameSource;
// if alternate state is viewed while card uses original
if (node.isIntrinsic() && node.cardState != null && node.cardState.getCard() == node.getHostCard()) {
nameSource = node.cardState;
} else {
nameSource = node.getHostCard();
}
ITranslatable nameSource = getHostName(node);
desc = CardTranslation.translateMultipleDescriptionText(desc, nameSource);
String translatedName = CardTranslation.getTranslatedName(nameSource);
desc = TextUtil.fastReplace(desc, "CARDNAME", translatedName);

View File

@@ -183,12 +183,7 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
@Override
public final String toString() {
if (hasParam("Description") && !this.isSuppressed()) {
ITranslatable nameSource;
if (this.isIntrinsic() && cardState != null && cardState.getCard() == getHostCard()) {
nameSource = cardState;
} else {
nameSource = getHostCard();
}
ITranslatable nameSource = getHostName(this);
String desc = CardTranslation.translateSingleDescriptionText(getParam("Description"), nameSource);
String translatedName = CardTranslation.getTranslatedName(nameSource);
desc = TextUtil.fastReplace(desc, "CARDNAME", translatedName);

View File

@@ -120,12 +120,7 @@ public abstract class Trigger extends TriggerReplacementBase {
public String toString(boolean active) {
if (hasParam("TriggerDescription") && !this.isSuppressed()) {
StringBuilder sb = new StringBuilder();
ITranslatable nameSource;
if (this.isIntrinsic() && cardState != null && cardState.getCard() == getHostCard()) {
nameSource = cardState;
} else {
nameSource = getHostCard();
}
ITranslatable nameSource = getHostName(this);
String desc = getParam("TriggerDescription");
if (!desc.contains("ABILITY")) {
desc = CardTranslation.translateSingleDescriptionText(getParam("TriggerDescription"), nameSource);

View File

@@ -544,7 +544,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
sp.getActivatingPlayer().setActivateLoyaltyAbilityThisTurn(true);
}
game.updateStackForView();
game.fireEvent(new GameEventSpellAbilityCast(sp, si, stackIndex, false));
game.fireEvent(new GameEventSpellAbilityCast(sp, si, stackIndex));
return si;
}

View File

@@ -25,7 +25,9 @@ public class DeckSetFilter extends DeckFormatFilter {
public DeckSetFilter(ItemManager<? super DeckProxy> itemManager0, Collection<String> sets0,
Collection<String> limitedSets0, boolean allowReprints0) {
this(itemManager0, sets0, allowReprints0);
this.limitedSets.addAll(limitedSets0);
if (limitedSets0 != null) {
this.limitedSets.addAll(limitedSets0);
}
}
@Override

View File

@@ -3,6 +3,6 @@ ManaCost:1 G G
Types:Creature Lizard
PT:2/3
T:Mode$ ChangesZone | Origin$ Graveyard | Destination$ Hand | ValidCard$ Card.Self | Execute$ TrigGainLife | TriggerDescription$ When CARDNAME is put into your hand from your graveyard, you gain 2 life.
K:Dredge:2
SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 2
K:Dredge:2
Oracle:When Golgari Brownscale is put into your hand from your graveyard, you gain 2 life.\nDredge 2 (If you would draw a card, you may mill two cards instead. If you do, return this card from your graveyard to your hand.)