Merge pull request #125 from tool4ever/attackingFix

Fix a couple of interactions
This commit is contained in:
Agetian
2022-04-24 07:50:44 +03:00
committed by GitHub
8 changed files with 32 additions and 25 deletions

View File

@@ -642,21 +642,19 @@ public class AiController {
// Ideally this should cast canPlaySa to determine that the AI is truly able/willing to cast a spell, // Ideally this should cast canPlaySa to determine that the AI is truly able/willing to cast a spell,
// but that is currently difficult to implement due to various side effects leading to stack overflow. // but that is currently difficult to implement due to various side effects leading to stack overflow.
Card host = sa.getHostCard(); Card host = sa.getHostCard();
if (!ComputerUtil.castPermanentInMain1(player, sa) && host != null && !host.isLand() && ComputerUtilCost.canPayCost(sa, player, false)) { if (sa instanceof SpellPermanent && host != null && !host.isLand() && !ComputerUtil.castPermanentInMain1(player, sa) && ComputerUtilCost.canPayCost(sa, player, false)) {
if (sa instanceof SpellPermanent) { return sa;
return sa;
}
} }
} }
return null; return null;
} }
public boolean reserveManaSources(SpellAbility sa) {
return reserveManaSources(sa, PhaseType.MAIN2, false, false, null);
}
public boolean reserveManaSourcesForNextSpell(SpellAbility sa, SpellAbility exceptForSa) { public boolean reserveManaSourcesForNextSpell(SpellAbility sa, SpellAbility exceptForSa) {
return reserveManaSources(sa, null, false, true, exceptForSa); return reserveManaSources(sa, null, false, true, exceptForSa);
} }
public boolean reserveManaSources(SpellAbility sa) {
return reserveManaSources(sa, PhaseType.MAIN2, false, false, null);
}
public boolean reserveManaSources(SpellAbility sa, PhaseType phaseType, boolean enemy) { public boolean reserveManaSources(SpellAbility sa, PhaseType phaseType, boolean enemy) {
return reserveManaSources(sa, phaseType, enemy, true, null); return reserveManaSources(sa, phaseType, enemy, true, null);
} }

View File

@@ -1676,7 +1676,7 @@ public class ComputerUtil {
// Lethal Damage => prevent damage/regeneration/bounce/shroud // Lethal Damage => prevent damage/regeneration/bounce/shroud
if (threatApi == ApiType.DealDamage || threatApi == ApiType.DamageAll) { if (threatApi == ApiType.DealDamage || threatApi == ApiType.DamageAll) {
// If PredictDamage is >= Lethal Damage // If PredictDamage is >= Lethal Damage
final int dmg = AbilityUtils.calculateAmount(topStack.getHostCard(), final int dmg = AbilityUtils.calculateAmount(source,
topStack.getParam("NumDmg"), topStack); topStack.getParam("NumDmg"), topStack);
final SpellAbility sub = topStack.getSubAbility(); final SpellAbility sub = topStack.getSubAbility();
boolean noRegen = false; boolean noRegen = false;
@@ -1756,7 +1756,7 @@ public class ComputerUtil {
&& (saviourApi == ApiType.ChangeZone || saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll && (saviourApi == ApiType.ChangeZone || saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll
|| saviourApi == ApiType.Protection || saviourApi == ApiType.PutCounter || saviourApi == ApiType.PutCounterAll || saviourApi == ApiType.Protection || saviourApi == ApiType.PutCounter || saviourApi == ApiType.PutCounterAll
|| saviourApi == null)) { || saviourApi == null)) {
final int dmg = -AbilityUtils.calculateAmount(topStack.getHostCard(), final int dmg = -AbilityUtils.calculateAmount(source,
topStack.getParam("NumDef"), topStack); topStack.getParam("NumDef"), topStack);
for (final Object o : objects) { for (final Object o : objects) {
if (o instanceof Card) { if (o instanceof Card) {

View File

@@ -11,7 +11,6 @@ import forge.ai.AiController;
import forge.ai.ComputerUtil; import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard; import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat; import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilMana;
import forge.ai.PlayerControllerAi; import forge.ai.PlayerControllerAi;
import forge.ai.SpecialCardAi; import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
@@ -122,8 +121,8 @@ public class EffectAi extends SpellAbilityAi {
randomReturn = true; randomReturn = true;
} else if (logic.equals("WillCastCreature") && ai.isAI()) { } else if (logic.equals("WillCastCreature") && ai.isAI()) {
AiController aic = ((PlayerControllerAi)ai.getController()).getAi(); AiController aic = ((PlayerControllerAi)ai.getController()).getAi();
SpellAbility saCreature = aic.predictSpellToCastInMain2(ApiType.PermanentCreature); SpellAbility saCreature = aic.predictSpellToCastInMain2(ApiType.PermanentNoncreature);
randomReturn = saCreature != null && ComputerUtilMana.canPayManaCost(saCreature, ai, 0, false); randomReturn = saCreature != null;
} else if (logic.equals("Always")) { } else if (logic.equals("Always")) {
randomReturn = true; randomReturn = true;
} else if (logic.equals("Main1")) { } else if (logic.equals("Main1")) {

View File

@@ -42,7 +42,7 @@ public class PermanentAi extends SpellAbilityAi {
} }
// Wait for Main2 if possible // Wait for Main2 if possible
return !ph.is(PhaseType.MAIN1) || !ph.isPlayerTurn(ai) || ComputerUtil.castPermanentInMain1(ai, sa) || sa.hasParam("WithoutManaCost"); return !ph.is(PhaseType.MAIN1) || !ph.isPlayerTurn(ai) || sa.hasParam("WithoutManaCost") || ComputerUtil.castPermanentInMain1(ai, sa);
} }
/** /**

View File

@@ -2762,14 +2762,22 @@ public class AbilityUtils {
String[] paidparts = l[0].split("\\$", 2); String[] paidparts = l[0].split("\\$", 2);
String[] lparts = paidparts[0].split(" ", 2); String[] lparts = paidparts[0].split(" ", 2);
final CardCollectionView cardsInZones = lparts[0].length() > 5 final CardCollectionView cardsInZones;
? game.getCardsIn(ZoneType.listValueOf(lparts[0].substring(5))) if (lparts[0].contains("All")) {
: game.getCardsIn(ZoneType.Battlefield); cardsInZones = game.getCardsInGame();
} else {
if (paidparts.length > 1) { cardsInZones = lparts[0].length() > 5
return doXMath(handlePaid(CardLists.getValidCards(cardsInZones, lparts[1], player, c, ctb), paidparts[1], c, ctb), expr, c, ctb); ? game.getCardsIn(ZoneType.listValueOf(lparts[0].substring(5)))
: game.getCardsIn(ZoneType.Battlefield);
} }
return doXMath(CardLists.getValidCardCount(cardsInZones, lparts[1], player, c, ctb), expr, c, ctb);
int cnt;
if (paidparts.length > 1) {
cnt = handlePaid(CardLists.getValidCards(cardsInZones, lparts[1], player, c, ctb), paidparts[1], c, ctb);
} else {
cnt = CardLists.getValidCardCount(cardsInZones, lparts[1], player, c, ctb);
}
return doXMath(cnt, expr, c, ctb);
} }
if (sq[0].startsWith("MostCardName")) { if (sq[0].startsWith("MostCardName")) {

View File

@@ -156,7 +156,7 @@ public class RepeatEachEffect extends SpellAbilityEffect {
continue; continue;
} }
if (nextTurn) { if (nextTurn) {
game.getUntap().addUntil(p, new GameCommand() { game.getCleanup().addUntil(p, new GameCommand() {
@Override @Override
public void run() { public void run() {
List<Object> tempRemembered = Lists.newArrayList(Iterables.filter(source.getRemembered(), Player.class)); List<Object> tempRemembered = Lists.newArrayList(Iterables.filter(source.getRemembered(), Player.class));

View File

@@ -1485,7 +1485,9 @@ public class CardProperty {
// These predicated refer to ongoing combat. If no combat happens, they'll return false (meaning not attacking/blocking ATM) // These predicated refer to ongoing combat. If no combat happens, they'll return false (meaning not attacking/blocking ATM)
else if (property.startsWith("attacking")) { else if (property.startsWith("attacking")) {
if (null == combat) return false; if (null == combat) return false;
if (property.equals("attacking")) return card.isAttacking(); // check this always first to make sure lki is only used when the card provides it
if (!(property.contains("LKI") ? lki : card).isAttacking()) return false;
if (property.equals("attacking")) return true;
if (property.equals("attackingYou")) return combat.isAttacking(card, sourceController); if (property.equals("attackingYou")) return combat.isAttacking(card, sourceController);
if (property.equals("attackingSame")) { if (property.equals("attackingSame")) {
final GameEntity attacked = combat.getDefenderByAttacker(source); final GameEntity attacked = combat.getDefenderByAttacker(source);
@@ -1493,7 +1495,7 @@ public class CardProperty {
return false; return false;
} }
} }
if (property.equals("attackingYouOrYourPW")) { if (property.startsWith("attackingYouOrYourPW")) {
GameEntity defender = combat.getDefenderByAttacker(card); GameEntity defender = combat.getDefenderByAttacker(card);
if (defender instanceof Card) { if (defender instanceof Card) {
// attack on a planeswalker that was removed from combat // attack on a planeswalker that was removed from combat

View File

@@ -3,8 +3,8 @@ ManaCost:3 W
Types:Legendary Creature Human Cleric Types:Legendary Creature Human Cleric
PT:2/4 PT:2/4
K:Lifelink K:Lifelink
T:Mode$ AttackersDeclared | AttackingPlayer$ Player.Opponent | CheckSVar$ X | SVarCompare$ GE2 | Execute$ TrigDraw | TriggerZones$ Battlefield | NoResolvingCheck$ True | TriggerDescription$ Whenever an opponent attacks with creatures, if two or more of those creatures are attacking you and/or planeswalkers you control, draw a card. T:Mode$ AttackersDeclared | AttackingPlayer$ Player.Opponent | CheckSVar$ X | SVarCompare$ GE2 | Execute$ TrigDraw | TriggerZones$ Battlefield | TriggerDescription$ Whenever an opponent attacks with creatures, if two or more of those creatures are attacking you and/or planeswalkers you control, draw a card.
SVar:X:Count$Valid Creature.attackingYouOrYourPW SVar:X:Count$ValidAll Creature.attackingYouOrYourPWLKI
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1 SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1
T:Mode$ SpellCast | ValidActivatingPlayer$ Opponent | ActivatorThisTurnCast$ EQ2 | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever an opponent casts their second spell each turn, draw a card. T:Mode$ SpellCast | ValidActivatingPlayer$ Opponent | ActivatorThisTurnCast$ EQ2 | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever an opponent casts their second spell each turn, draw a card.
Oracle:Lifelink\nWhenever an opponent attacks with creatures, if two or more of those creatures are attacking you and/or planeswalkers you control, draw a card.\nWhenever an opponent casts their second spell each turn, draw a card. Oracle:Lifelink\nWhenever an opponent attacks with creatures, if two or more of those creatures are attacking you and/or planeswalkers you control, draw a card.\nWhenever an opponent casts their second spell each turn, draw a card.