Merge branch 'gauntletfix' into 'master'

Fix some more NPE related to gauntlets

See merge request core-developers/forge!5583
This commit is contained in:
Michael Kamensky
2021-10-18 16:27:26 +00:00
14 changed files with 36 additions and 46 deletions

View File

@@ -1910,11 +1910,7 @@ public class ComputerUtil {
* @return true if the creature dies according to current board position. * @return true if the creature dies according to current board position.
*/ */
public static boolean predictCreatureWillDieThisTurn(final Player ai, final Card creature, final SpellAbility excludeSa) { public static boolean predictCreatureWillDieThisTurn(final Player ai, final Card creature, final SpellAbility excludeSa) {
final Game game = creature.getGame(); final Game game = ai.getGame();
// a creature will die as a result of combat
boolean willDieInCombat = game.getPhaseHandler().inCombat()
&& ComputerUtilCombat.combatantWouldBeDestroyed(creature.getController(), creature, game.getCombat());
// a creature will [hopefully] die from a spell on stack // a creature will [hopefully] die from a spell on stack
boolean willDieFromSpell = false; boolean willDieFromSpell = false;
@@ -1933,6 +1929,10 @@ public class ComputerUtil {
} }
willDieFromSpell = !noStackCheck && predictThreatenedObjects(creature.getController(), excludeSa).contains(creature); willDieFromSpell = !noStackCheck && predictThreatenedObjects(creature.getController(), excludeSa).contains(creature);
// a creature will die as a result of combat
boolean willDieInCombat = !willDieFromSpell && game.getPhaseHandler().inCombat()
&& ComputerUtilCombat.combatantWouldBeDestroyed(creature.getController(), creature, game.getCombat());
return willDieInCombat || willDieFromSpell; return willDieInCombat || willDieFromSpell;
} }

View File

@@ -750,7 +750,6 @@ public class ComputerUtilCard {
for (final Entry<String, Integer> entry : map.entrySet()) { for (final Entry<String, Integer> entry : map.entrySet()) {
final String type = entry.getKey(); final String type = entry.getKey();
// Log.debug(type + " - " + entry.getValue());
if (max < entry.getValue()) { if (max < entry.getValue()) {
max = entry.getValue(); max = entry.getValue();
@@ -784,7 +783,6 @@ public class ComputerUtilCard {
// TODO JAVA 8 use getOrDefault // TODO JAVA 8 use getOrDefault
for (final Card c : list) { for (final Card c : list) {
// Changeling are all creature types, they are not interesting for // Changeling are all creature types, they are not interesting for
// counting creature types // counting creature types
if (c.hasStartOfKeyword(Keyword.CHANGELING.toString())) { if (c.hasStartOfKeyword(Keyword.CHANGELING.toString())) {

View File

@@ -19,7 +19,6 @@ public class GoadAi extends SpellAbilityAi {
@Override @Override
protected boolean checkApiLogic(final Player ai, final SpellAbility sa) { protected boolean checkApiLogic(final Player ai, final SpellAbility sa) {
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
final Game game = source.getGame(); final Game game = source.getGame();

View File

@@ -25,7 +25,6 @@ public class MustAttackAi extends SpellAbilityAi {
*/ */
@Override @Override
protected boolean doTriggerAINoCost(Player aiPlayer, SpellAbility sa, boolean mandatory) { protected boolean doTriggerAINoCost(Player aiPlayer, SpellAbility sa, boolean mandatory) {
boolean chance; boolean chance;
// TODO - implement AI // TODO - implement AI

View File

@@ -160,7 +160,6 @@ public class MustBlockAi extends SpellAbilityAi {
private List<Card> determineGoodBlockers(final Card attacker, final Player ai, Player defender, SpellAbility sa, private List<Card> determineGoodBlockers(final Card attacker, final Player ai, Player defender, SpellAbility sa,
final boolean onlyLethal, final boolean testTapped) { final boolean onlyLethal, final boolean testTapped) {
List<Card> list = Lists.newArrayList(); List<Card> list = Lists.newArrayList();
list = CardLists.filter(defender.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES); list = CardLists.filter(defender.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES);

View File

@@ -42,8 +42,7 @@ public class PermanentNoncreatureAi extends PermanentAi {
CardCollection targets = CardLists.getTargetableCards(game.getCardsIn(origin), effectExile); CardCollection targets = CardLists.getTargetableCards(game.getCardsIn(origin), effectExile);
if (sourceName.equals("Suspension Field") if (sourceName.equals("Suspension Field")
|| sourceName.equals("Detention Sphere")) { || sourceName.equals("Detention Sphere")) {
// existing "exile until leaves" enchantments only target // existing "exile until leaves" enchantments only target opponent's permanents
// opponent's permanents
// TODO: consider replacing the condition with host.hasSVar("OblivionRing") // TODO: consider replacing the condition with host.hasSVar("OblivionRing")
targets = CardLists.filterControlledBy(targets, ai.getOpponents()); targets = CardLists.filterControlledBy(targets, ai.getOpponents());
} }

View File

@@ -38,9 +38,4 @@ public class RestartGameAi extends SpellAbilityAi {
return false; return false;
} }
@Override
protected boolean doTriggerAINoCost(Player aiPlayer, SpellAbility sa, boolean mandatory) {
// This trigger AI is completely unused, but return true just in case
return true;
}
} }

View File

@@ -197,13 +197,7 @@ public class DamageDealEffect extends DamageBaseEffect {
return; return;
} }
CardCollection assigneeCards = new CardCollection(); CardCollection assigneeCards = new CardCollection(Iterables.filter(tgts, Card.class));
// Do we have a way of doing this in a better fashion?
for (GameObject obj : tgts) {
if (obj instanceof Card) {
assigneeCards.add((Card) obj);
}
}
Player assigningPlayer = players.get(0); Player assigningPlayer = players.get(0);
Map<Card, Integer> map = assigningPlayer.getController().assignCombatDamage(sourceLKI, assigneeCards, dmg, null, true); Map<Card, Integer> map = assigningPlayer.getController().assignCombatDamage(sourceLKI, assigneeCards, dmg, null, true);

View File

@@ -122,8 +122,8 @@ public enum CSubmenuGauntletBuild implements ICDoc {
} }
private void addDeck() { private void addDeck() {
final Deck deckToAdd = view.getLstLeft().getPlayer().getDeck(); final Deck deckToAdd = view.getLstLeft().getPlayer() != null ? view.getLstLeft().getPlayer().getDeck() : null;
if ( null == deckToAdd ) { if (null == deckToAdd) {
return; return;
} }
workingDecks.add(deckToAdd); workingDecks.add(deckToAdd);
@@ -145,7 +145,7 @@ public enum CSubmenuGauntletBuild implements ICDoc {
private void deckUp() { private void deckUp() {
final int oldIndex = view.getLstRight().getSelectedIndex(); final int oldIndex = view.getLstRight().getSelectedIndex();
if (oldIndex == 0) { return; } if (oldIndex <= 0) { return; }
final Deck movingDeck = workingDecks.remove(oldIndex); final Deck movingDeck = workingDecks.remove(oldIndex);
workingDecks.add(oldIndex - 1, movingDeck); workingDecks.add(oldIndex - 1, movingDeck);

View File

@@ -1,6 +1,6 @@
Name:Bounding Wolf Name:Bounding Wolf
ManaCost:2 G ManaCost:2 G
Types:Creature wolf Types:Creature Wolf
PT:3/2 PT:3/2
K:Flash K:Flash
K:Reach K:Reach

View File

@@ -8,7 +8,8 @@ A:AB$ DealDamage | Cost$ T | SubAbility$ TapWolves | ValidTgts$ Creature | NumDm
SVar:TapWolves:DB$ TapAll | ValidCards$ Creature.Wolf+YouCtrl+untapped | RememberTapped$ True | SubAbility$ WildHuntDamage | StackDescription$ None SVar:TapWolves:DB$ TapAll | ValidCards$ Creature.Wolf+YouCtrl+untapped | RememberTapped$ True | SubAbility$ WildHuntDamage | StackDescription$ None
SVar:WildHuntDamage:DB$ RepeatEach | RepeatSubAbility$ WolfStrike | UseImprinted$ True | RepeatCards$ Card.IsRemembered | DamageMap$ True | SubAbility$ HuntedDamage | StackDescription$ None SVar:WildHuntDamage:DB$ RepeatEach | RepeatSubAbility$ WolfStrike | UseImprinted$ True | RepeatCards$ Card.IsRemembered | DamageMap$ True | SubAbility$ HuntedDamage | StackDescription$ None
SVar:WolfStrike:DB$ DealDamage | DamageSource$ Imprinted | NumDmg$ X | Defined$ ParentTarget | StackDescription$ None SVar:WolfStrike:DB$ DealDamage | DamageSource$ Imprinted | NumDmg$ X | Defined$ ParentTarget | StackDescription$ None
SVar:HuntedDamage:DB$ DealDamage | DamageSource$ ParentTarget | NumDmg$ Y | DividerOnResolution$ ParentTargetedController | Defined$ Remembered | StackDescription$ None SVar:HuntedDamage:DB$ DealDamage | DamageSource$ ParentTarget | NumDmg$ Y | DividerOnResolution$ ParentTargetedController | Defined$ Remembered | SubAbility$ DBDamageResolve | StackDescription$ None
SVar:DBDamageResolve:DB$ DamageResolve
SVar:X:Imprinted$CardPower SVar:X:Imprinted$CardPower
SVar:Y:Targeted$CardPower SVar:Y:Targeted$CardPower
SVar:Picture:http://www.wizards.com/global/images/magic/general/master_of_the_wild_hunt.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/master_of_the_wild_hunt.jpg

View File

@@ -425,6 +425,8 @@ public class DeckgenUtil {
/** @return {@link forge.deck.Deck} */ /** @return {@link forge.deck.Deck} */
public static Deck getRandomCustomDeck() { public static Deck getRandomCustomDeck() {
final IStorage<Deck> allDecks = FModel.getDecks().getConstructed(); final IStorage<Deck> allDecks = FModel.getDecks().getConstructed();
// in case user has not created any yet
if (allDecks.size() == 0) { return null; }
final int rand = (int) (Math.floor(MyRandom.getRandom().nextDouble() * allDecks.size())); final int rand = (int) (Math.floor(MyRandom.getRandom().nextDouble() * allDecks.size()));
final String name = allDecks.getItemNames().toArray(new String[0])[rand]; final String name = allDecks.getItemNames().toArray(new String[0])[rand];
return allDecks.get(name); return allDecks.get(name);

View File

@@ -59,8 +59,10 @@ public class GauntletUtil {
break; break;
case CUSTOM_DECK: case CUSTOM_DECK:
deck = DeckgenUtil.getRandomCustomDeck(); deck = DeckgenUtil.getRandomCustomDeck();
if (deck != null) { // fall back to precon if none available
eventNames.add(deck.getName()); eventNames.add(deck.getName());
break; break;
}
case PRECONSTRUCTED_DECK: case PRECONSTRUCTED_DECK:
deck = DeckgenUtil.getRandomPreconDeck(); deck = DeckgenUtil.getRandomPreconDeck();
eventNames.add(deck.getName()); eventNames.add(deck.getName());

View File

@@ -56,8 +56,10 @@ public class TournamentUtil {
break; break;
case CUSTOM_DECK: case CUSTOM_DECK:
deck = DeckgenUtil.getRandomCustomDeck(); deck = DeckgenUtil.getRandomCustomDeck();
if (deck != null) { // fall back to precon if none available
eventNames.add(deck.getName()); eventNames.add(deck.getName());
break; break;
}
case PRECONSTRUCTED_DECK: case PRECONSTRUCTED_DECK:
deck = DeckgenUtil.getRandomPreconDeck(); deck = DeckgenUtil.getRandomPreconDeck();
eventNames.add(deck.getName()); eventNames.add(deck.getName());