mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 18:58:00 +00:00
Merge branch 'junk' into 'master'
Fix Junk Winder See merge request core-developers/forge!5534
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ public class CloneAi extends SpellAbilityAi {
|
|||||||
chance = cloneTgtAI(sa);
|
chance = cloneTgtAI(sa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return chance;
|
return chance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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)) {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user