Merge branch 'junk' into 'master'

Fix Junk Winder

See merge request core-developers/forge!5534
This commit is contained in:
Michael Kamensky
2021-10-10 04:46:41 +00:00
12 changed files with 19 additions and 36 deletions

View File

@@ -347,7 +347,7 @@ public class AiBlockController {
// Try to block an attacker without first strike with a gang of first strikers // Try to block an attacker without first strike with a gang of first strikers
for (final Card attacker : attackersLeft) { for (final Card attacker : attackersLeft) {
if (ComputerUtilCombat.attackerCantBeDestroyedInCombat(ai, attacker)) { if (ComputerUtilCombat.combatantCantBeDestroyed(ai, attacker)) {
// don't bother with gang blocking if the attacker will regenerate or is indestructible // don't bother with gang blocking if the attacker will regenerate or is indestructible
continue; continue;
} }
@@ -395,7 +395,7 @@ public class AiBlockController {
// Try to block an attacker with two blockers of which only one will die // Try to block an attacker with two blockers of which only one will die
for (final Card attacker : attackersLeft) { for (final Card attacker : attackersLeft) {
if (ComputerUtilCombat.attackerCantBeDestroyedInCombat(ai, attacker)) { if (ComputerUtilCombat.combatantCantBeDestroyed(ai, attacker)) {
// don't bother with gang blocking if the attacker will regenerate or is indestructible // don't bother with gang blocking if the attacker will regenerate or is indestructible
continue; continue;
} }

View File

@@ -605,7 +605,6 @@ public class ComputerUtilCombat {
int flankingMagnitude = 0; int flankingMagnitude = 0;
if (attacker.hasKeyword(Keyword.FLANKING) && !defender.hasKeyword(Keyword.FLANKING)) { if (attacker.hasKeyword(Keyword.FLANKING) && !defender.hasKeyword(Keyword.FLANKING)) {
flankingMagnitude = attacker.getAmountOfKeyword(Keyword.FLANKING); flankingMagnitude = attacker.getAmountOfKeyword(Keyword.FLANKING);
if (flankingMagnitude >= defender.getNetToughness()) { if (flankingMagnitude >= defender.getNetToughness()) {
@@ -1641,30 +1640,25 @@ public class ComputerUtilCombat {
return false; return false;
} }
// can the attacker be potentially destroyed in combat or is it potentially indestructible? // can the combatant be potentially destroyed or is it potentially indestructible?
/** /**
* <p> * <p>
* attackerCantBeDestroyedNow. * attackerCantBeDestroyedNow.
* </p> * </p>
* @param ai * @param ai
* *
* @param attacker * @param combatant
* a {@link forge.game.card.Card} object. * a {@link forge.game.card.Card} object.
* @return a boolean. * @return a boolean.
*/ */
public static boolean attackerCantBeDestroyedInCombat(Player ai, final Card attacker) { public static boolean combatantCantBeDestroyed(Player ai, final Card combatant) {
// attacker is either indestructible or may regenerate // either indestructible or may regenerate
if (attacker.hasKeyword(Keyword.INDESTRUCTIBLE) || (ComputerUtil.canRegenerate(ai, attacker))) { if (combatant.hasKeyword(Keyword.INDESTRUCTIBLE) || (ComputerUtil.canRegenerate(ai, combatant))) {
return true; return true;
} }
// attacker will regenerate // will regenerate
if (attacker.getShieldCount() > 0 && attacker.canBeShielded()) { if (combatant.getShieldCount() > 0 && combatant.canBeShielded()) {
return true;
}
// all damage will be prevented
if (attacker.hasKeyword("PreventAllDamageBy Creature.blockingSource")) {
return true; return true;
} }
@@ -1709,7 +1703,6 @@ public class ComputerUtilCombat {
int flankingMagnitude = 0; int flankingMagnitude = 0;
if (attacker.hasKeyword(Keyword.FLANKING) && !blocker.hasKeyword(Keyword.FLANKING)) { if (attacker.hasKeyword(Keyword.FLANKING) && !blocker.hasKeyword(Keyword.FLANKING)) {
flankingMagnitude = attacker.getAmountOfKeyword(Keyword.FLANKING); flankingMagnitude = attacker.getAmountOfKeyword(Keyword.FLANKING);
if (flankingMagnitude >= blocker.getNetToughness()) { if (flankingMagnitude >= blocker.getNetToughness()) {
@@ -1730,10 +1723,6 @@ public class ComputerUtilCombat {
return false; return false;
} }
if (attacker.hasKeyword("PreventAllDamageBy Creature.blockingSource")) {
return false;
}
int defenderDamage; int defenderDamage;
int attackerDamage; int attackerDamage;
if (blocker.toughnessAssignsDamage()) { if (blocker.toughnessAssignsDamage()) {

View File

@@ -344,7 +344,7 @@ public class SpecialAiLogic {
return false; return false;
} }
final boolean sourceCantDie = ComputerUtilCombat.attackerCantBeDestroyedInCombat(ai, source); final boolean sourceCantDie = ComputerUtilCombat.combatantCantBeDestroyed(ai, source);
final int minDefT = Aggregates.min(combat.getBlockers(source), CardPredicates.Accessors.fnGetNetToughness); final int minDefT = Aggregates.min(combat.getBlockers(source), CardPredicates.Accessors.fnGetNetToughness);
final int DefP = sourceCantDie ? 0 : Aggregates.sum(combat.getBlockers(source), CardPredicates.Accessors.fnGetNetPower); final int DefP = sourceCantDie ? 0 : Aggregates.sum(combat.getBlockers(source), CardPredicates.Accessors.fnGetNetPower);

View File

@@ -399,7 +399,7 @@ public class SpecialCardAi {
} }
boolean isBlocking = combat.isBlocking(source); boolean isBlocking = combat.isBlocking(source);
boolean cantDie = ComputerUtilCombat.attackerCantBeDestroyedInCombat(ai, source); boolean cantDie = ComputerUtilCombat.combatantCantBeDestroyed(ai, source);
CardCollection opposition = isBlocking ? combat.getAttackersBlockedBy(source) : combat.getBlockers(source); CardCollection opposition = isBlocking ? combat.getAttackersBlockedBy(source) : combat.getBlockers(source);
int oppP = Aggregates.sum(opposition, CardPredicates.Accessors.fnGetAttack); int oppP = Aggregates.sum(opposition, CardPredicates.Accessors.fnGetAttack);
@@ -433,7 +433,7 @@ public class SpecialCardAi {
if (c.hasKeyword(Keyword.FIRST_STRIKE) || c.hasKeyword(Keyword.DOUBLE_STRIKE)) { if (c.hasKeyword(Keyword.FIRST_STRIKE) || c.hasKeyword(Keyword.DOUBLE_STRIKE)) {
oppHasFirstStrike = true; oppHasFirstStrike = true;
} }
if (!ComputerUtilCombat.attackerCantBeDestroyedInCombat(c.getController(), c)) { if (!ComputerUtilCombat.combatantCantBeDestroyed(c.getController(), c)) {
oppCantDie = false; oppCantDie = false;
} }
} }

View File

@@ -92,7 +92,6 @@ public class CloneAi extends SpellAbilityAi {
chance = cloneTgtAI(sa); chance = cloneTgtAI(sa);
} }
return chance; return chance;
} }

View File

@@ -25,8 +25,7 @@ public class CountersPutAllAi extends SpellAbilityAi {
@Override @Override
protected boolean canPlayAI(Player ai, SpellAbility sa) { protected boolean canPlayAI(Player ai, SpellAbility sa) {
// AI needs to be expanded, since this function can be pretty complex // AI needs to be expanded, since this function can be pretty complex
// based on what // based on what the expected targets could be
// the expected targets could be
final Cost abCost = sa.getPayCosts(); final Cost abCost = sa.getPayCosts();
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
List<Card> hList; List<Card> hList;

View File

@@ -103,7 +103,6 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
CardCollection countersList = CardLists.filter(list, CardPredicates.hasCounters()); CardCollection countersList = CardLists.filter(list, CardPredicates.hasCounters());
if (!countersList.isEmpty()) { if (!countersList.isEmpty()) {
if (!ai.isCardInPlay("Marit Lage") || noLegendary) { if (!ai.isCardInPlay("Marit Lage") || noLegendary) {
CardCollectionView depthsList = CardLists.filter(countersList, CardCollectionView depthsList = CardLists.filter(countersList,
CardPredicates.nameEquals("Dark Depths"), CardPredicates.hasCounter(CounterEnumType.ICE)); CardPredicates.nameEquals("Dark Depths"), CardPredicates.hasCounter(CounterEnumType.ICE));

View File

@@ -25,8 +25,7 @@ public class DamagePreventAllAi extends SpellAbilityAi {
} }
if (!ai.getGame().getStack().isEmpty()) { if (!ai.getGame().getStack().isEmpty()) {
// TODO check stack for something on the stack will kill anything i // TODO check stack for something on the stack will kill anything i control
// control
} // Protect combatants } // Protect combatants
else if (ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) { else if (ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {

View File

@@ -126,8 +126,7 @@ public class PermanentAi extends SpellAbilityAi {
sa.setXManaCostPaid(xPay); sa.setXManaCostPaid(xPay);
} }
} else if (mana.isZero()) { } else if (mana.isZero()) {
// if mana is zero, but card mana cost does have X, then something // if mana is zero, but card mana cost does have X, then something is wrong
// is wrong
ManaCost cardCost = card.getManaCost(); ManaCost cardCost = card.getManaCost();
if (cardCost != null && cardCost.countX() > 0) { if (cardCost != null && cardCost.countX() > 0) {
// AiPlayDecision.CantPlayAi // AiPlayDecision.CantPlayAi
@@ -266,7 +265,7 @@ public class PermanentAi extends SpellAbilityAi {
} else if (param.equals("OnlyFromZone")) { } else if (param.equals("OnlyFromZone")) {
if (!card.getZone().getZoneType().toString().equals(value)) { if (!card.getZone().getZoneType().toString().equals(value)) {
dontCast = true; dontCast = true;
break; // limit casting to a specific zone only break; // limit casting to a specific zone only
} }
} }
} }

View File

@@ -228,9 +228,9 @@ public abstract class PumpAiBase extends SpellAbilityAi {
// Use defensively to destroy the opposing Flying creature when possible, or to block with an indestructible // Use defensively to destroy the opposing Flying creature when possible, or to block with an indestructible
// creature buffed with Flying // creature buffed with Flying
for (Card c : attackingFlyer) { for (Card c : attackingFlyer) {
if (!ComputerUtilCombat.attackerCantBeDestroyedInCombat(c.getController(), c) if (!ComputerUtilCombat.combatantCantBeDestroyed(c.getController(), c)
&& (card.getNetPower() >= c.getNetToughness() && card.getNetToughness() > c.getNetPower() && (card.getNetPower() >= c.getNetToughness() && card.getNetToughness() > c.getNetPower()
|| ComputerUtilCombat.attackerCantBeDestroyedInCombat(ai, card))) { || ComputerUtilCombat.combatantCantBeDestroyed(ai, card))) {
return true; return true;
} }
} }

View File

@@ -143,7 +143,6 @@ public class SacrificeAi extends SpellAbilityAi {
// (or X for X) trades for special decks // (or X for X) trades for special decks
return humanList.size() >= amount; return humanList.size() >= amount;
} else if (defined.equals("You")) { } else if (defined.equals("You")) {
List<Card> computerList = null; List<Card> computerList = null;
try { try {
computerList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa); computerList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);

View File

@@ -2,7 +2,7 @@ Name:Junk Winder
ManaCost:5 U U ManaCost:5 U U
Types:Creature Serpent Types:Creature Serpent
PT:5/6 PT:5/6
K:Affinity:Permanent.token:token K:Affinity:Permanent.token+YouCtrl:token
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Permanent.token+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigTap | TriggerDescription$ Whenever a token enters the battlefield under your control, tap target nonland permanent an opponent controls. It doesn't untap during its controller's next untap step. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Permanent.token+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigTap | TriggerDescription$ Whenever a token enters the battlefield under your control, tap target nonland permanent an opponent controls. It doesn't untap during its controller's next untap step.
SVar:TrigTap:DB$ Tap | ValidTgts$ Permanent.nonLand+OppCtrl | TgtPrompt$ Choose target nonland permanent an opponent controls | SubAbility$ DBPump SVar:TrigTap:DB$ Tap | ValidTgts$ Permanent.nonLand+OppCtrl | TgtPrompt$ Choose target nonland permanent an opponent controls | SubAbility$ DBPump
SVar:DBPump:DB$ Pump | Defined$ Targeted | KW$ HIDDEN This card doesn't untap during your next untap step. | Duration$ Permanent SVar:DBPump:DB$ Pump | Defined$ Targeted | KW$ HIDDEN This card doesn't untap during your next untap step. | Duration$ Permanent