mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 18:58:00 +00:00
ST: CantAttach begins to replace other cases
This commit is contained in:
@@ -975,7 +975,7 @@ public class ComputerUtil {
|
|||||||
playNow = false;
|
playNow = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!playNow && c.isCreature() && ComputerUtilCombat.canAttackNextTurn(c) && c.canBeEquippedBy(card)) {
|
if (!playNow && c.isCreature() && ComputerUtilCombat.canAttackNextTurn(c) && c.canBeAttachedBy(card)) {
|
||||||
playNow = true;
|
playNow = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +240,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Acceptable choice.
|
* Acceptable choice.
|
||||||
*
|
*
|
||||||
* @param c
|
* @param c
|
||||||
* the c
|
* the c
|
||||||
* @param mandatory
|
* @param mandatory
|
||||||
@@ -265,7 +265,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Choose unpreferred.
|
* Choose unpreferred.
|
||||||
*
|
*
|
||||||
* @param mandatory
|
* @param mandatory
|
||||||
* the mandatory
|
* the mandatory
|
||||||
* @param list
|
* @param list
|
||||||
@@ -282,7 +282,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Choose less preferred.
|
* Choose less preferred.
|
||||||
*
|
*
|
||||||
* @param mandatory
|
* @param mandatory
|
||||||
* the mandatory
|
* the mandatory
|
||||||
* @param list
|
* @param list
|
||||||
@@ -299,7 +299,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach ai change type preference.
|
* Attach ai change type preference.
|
||||||
*
|
*
|
||||||
* @param sa
|
* @param sa
|
||||||
* the sa
|
* the sa
|
||||||
* @param list
|
* @param list
|
||||||
@@ -330,7 +330,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
list = CardLists.getNotType(list, type); // Filter out Basic Lands that have the same type as the changing type
|
list = CardLists.getNotType(list, type); // Filter out Basic Lands that have the same type as the changing type
|
||||||
|
|
||||||
// Don't target fetchlands
|
// Don't target fetchlands
|
||||||
list = CardLists.filter(list, new Predicate<Card>() {
|
list = CardLists.filter(list, new Predicate<Card>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -371,7 +371,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach ai keep tapped preference.
|
* Attach ai keep tapped preference.
|
||||||
*
|
*
|
||||||
* @param sa
|
* @param sa
|
||||||
* the sa
|
* the sa
|
||||||
* @param list
|
* @param list
|
||||||
@@ -499,7 +499,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach ai control preference.
|
* Attach ai control preference.
|
||||||
*
|
*
|
||||||
* @param sa
|
* @param sa
|
||||||
* the sa
|
* the sa
|
||||||
* @param list
|
* @param list
|
||||||
@@ -570,7 +570,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
c = ComputerUtilCard.getWorstAI(betterList);
|
c = ComputerUtilCard.getWorstAI(betterList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// If Mandatory (brought directly into play without casting) gotta
|
// If Mandatory (brought directly into play without casting) gotta
|
||||||
// choose something
|
// choose something
|
||||||
@@ -583,7 +583,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach ai reanimate preference.
|
* Attach ai reanimate preference.
|
||||||
*
|
*
|
||||||
* @param sa
|
* @param sa
|
||||||
* the sa
|
* the sa
|
||||||
* @param list
|
* @param list
|
||||||
@@ -670,7 +670,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Attach ai specific card preference.
|
* Attach ai specific card preference.
|
||||||
*
|
*
|
||||||
* @param sa
|
* @param sa
|
||||||
* the sa
|
* the sa
|
||||||
* @param list
|
* @param list
|
||||||
@@ -687,7 +687,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
final Player ai = sa.getActivatingPlayer();
|
final Player ai = sa.getActivatingPlayer();
|
||||||
final String sourceName = ComputerUtilAbility.getAbilitySourceName(sa);
|
final String sourceName = ComputerUtilAbility.getAbilitySourceName(sa);
|
||||||
Card chosen = null;
|
Card chosen = null;
|
||||||
|
|
||||||
if ("Guilty Conscience".equals(sourceName)) {
|
if ("Guilty Conscience".equals(sourceName)) {
|
||||||
chosen = SpecialCardAi.GuiltyConscience.getBestAttachTarget(ai, sa, list);
|
chosen = SpecialCardAi.GuiltyConscience.getBestAttachTarget(ai, sa, list);
|
||||||
} else if ("Bonds of Faith".equals(sourceName)) {
|
} else if ("Bonds of Faith".equals(sourceName)) {
|
||||||
@@ -746,7 +746,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
// Should generalize this code a bit since they all have similar structures
|
// Should generalize this code a bit since they all have similar structures
|
||||||
/**
|
/**
|
||||||
* Attach ai control preference.
|
* Attach ai control preference.
|
||||||
*
|
*
|
||||||
* @param sa
|
* @param sa
|
||||||
* the sa
|
* the sa
|
||||||
* @param list
|
* @param list
|
||||||
@@ -782,7 +782,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach ai highest evaluated preference.
|
* Attach ai highest evaluated preference.
|
||||||
*
|
*
|
||||||
* @param list the initial valid list
|
* @param list the initial valid list
|
||||||
* @return the card
|
* @return the card
|
||||||
*/
|
*/
|
||||||
@@ -792,7 +792,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach ai curse preference.
|
* Attach ai curse preference.
|
||||||
*
|
*
|
||||||
* @param sa
|
* @param sa
|
||||||
* the sa
|
* the sa
|
||||||
* @param list
|
* @param list
|
||||||
@@ -916,7 +916,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
* the sa
|
* the sa
|
||||||
* @param mandatory
|
* @param mandatory
|
||||||
* the mandatory
|
* the mandatory
|
||||||
*
|
*
|
||||||
* @return true, if successful
|
* @return true, if successful
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -986,7 +986,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach ai pump preference.
|
* Attach ai pump preference.
|
||||||
*
|
*
|
||||||
* @param sa
|
* @param sa
|
||||||
* the sa
|
* the sa
|
||||||
* @param list
|
* @param list
|
||||||
@@ -1066,7 +1066,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
list.removeAll(toRemove);
|
list.removeAll(toRemove);
|
||||||
|
|
||||||
if (magnetList != null) {
|
if (magnetList != null) {
|
||||||
|
|
||||||
// Look for Heroic triggers
|
// Look for Heroic triggers
|
||||||
if (magnetList.isEmpty() && sa.isSpell()) {
|
if (magnetList.isEmpty() && sa.isSpell()) {
|
||||||
for (Card target : list) {
|
for (Card target : list) {
|
||||||
@@ -1256,7 +1256,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach to card ai preferences.
|
* Attach to card ai preferences.
|
||||||
*
|
*
|
||||||
* @param sa
|
* @param sa
|
||||||
* the sa
|
* the sa
|
||||||
* @param sa
|
* @param sa
|
||||||
@@ -1275,6 +1275,12 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
if (attachSource.hasSVar("DontEquip")) {
|
if (attachSource.hasSVar("DontEquip")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// is no attachment so no using attach
|
||||||
|
if (!attachSource.isAttachment()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Don't fortify if already fortifying
|
// Don't fortify if already fortifying
|
||||||
if (attachSource.getAttachingCard() != null && attachSource.getAttachingCard().getController() == aiPlayer) {
|
if (attachSource.getAttachingCard() != null && attachSource.getAttachingCard().getController() == aiPlayer) {
|
||||||
return null;
|
return null;
|
||||||
@@ -1286,11 +1292,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
} else {
|
} else {
|
||||||
list = CardLists.getValidCards(aiPlayer.getGame().getCardsIn(tgt.getZone()), tgt.getValidTgts(), sa.getActivatingPlayer(), attachSource, sa);
|
list = CardLists.getValidCards(aiPlayer.getGame().getCardsIn(tgt.getZone()), tgt.getValidTgts(), sa.getActivatingPlayer(), attachSource, sa);
|
||||||
|
|
||||||
if (attachSource.isAura()) {
|
list = CardLists.filter(list, CardPredicates.canBeAttachedBy(attachSource));
|
||||||
list = CardLists.filter(list, CardPredicates.canBeEnchantedBy(attachSource));
|
|
||||||
} else if (attachSource.isEquipment()) {
|
|
||||||
list = CardLists.filter(list, CardPredicates.canBeEquippedBy(attachSource));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO If Attaching without casting, don't need to actually target.
|
// TODO If Attaching without casting, don't need to actually target.
|
||||||
// I believe this is the only case where mandatory will be true, so just
|
// I believe this is the only case where mandatory will be true, so just
|
||||||
@@ -1314,7 +1316,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
Card c = attachGeneralAI(aiPlayer, sa, prefList, mandatory, attachSource, sa.getParam("AILogic"));
|
Card c = attachGeneralAI(aiPlayer, sa, prefList, mandatory, attachSource, sa.getParam("AILogic"));
|
||||||
|
|
||||||
AiController aic = ((PlayerControllerAi)aiPlayer.getController()).getAi();
|
AiController aic = ((PlayerControllerAi)aiPlayer.getController()).getAi();
|
||||||
if (c != null && attachSource.isEquipment()
|
if (c != null && attachSource.isEquipment()
|
||||||
&& attachSource.isEquipping()
|
&& attachSource.isEquipping()
|
||||||
&& attachSource.getEquipping().getController() == aiPlayer) {
|
&& attachSource.getEquipping().getController() == aiPlayer) {
|
||||||
if (c.equals(attachSource.getEquipping())) {
|
if (c.equals(attachSource.getEquipping())) {
|
||||||
@@ -1338,7 +1340,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure to prioritize casting spells in main 2 (creatures, other equipment, etc.) rather than moving equipment around
|
// make sure to prioritize casting spells in main 2 (creatures, other equipment, etc.) rather than moving equipment around
|
||||||
boolean decideMoveFromUseless = uselessCreature && aic.getBooleanProperty(AiProps.PRIORITIZE_MOVE_EQUIPMENT_IF_USELESS);
|
boolean decideMoveFromUseless = uselessCreature && aic.getBooleanProperty(AiProps.PRIORITIZE_MOVE_EQUIPMENT_IF_USELESS);
|
||||||
|
|
||||||
@@ -1352,7 +1354,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
// avoid randomly moving the equipment back and forth between several creatures in one turn
|
// avoid randomly moving the equipment back and forth between several creatures in one turn
|
||||||
if (AiCardMemory.isRememberedCard(aiPlayer, sa.getHostCard(), AiCardMemory.MemorySet.ATTACHED_THIS_TURN)) {
|
if (AiCardMemory.isRememberedCard(aiPlayer, sa.getHostCard(), AiCardMemory.MemorySet.ATTACHED_THIS_TURN)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// do not equip if the new creature is not significantly better than the previous one (evaluates at least better by evalT)
|
// do not equip if the new creature is not significantly better than the previous one (evaluates at least better by evalT)
|
||||||
int evalT = aic.getIntProperty(AiProps.MOVE_EQUIPMENT_CREATURE_EVAL_THRESHOLD);
|
int evalT = aic.getIntProperty(AiProps.MOVE_EQUIPMENT_CREATURE_EVAL_THRESHOLD);
|
||||||
@@ -1360,7 +1362,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AiCardMemory.rememberCard(aiPlayer, sa.getHostCard(), AiCardMemory.MemorySet.ATTACHED_THIS_TURN);
|
AiCardMemory.rememberCard(aiPlayer, sa.getHostCard(), AiCardMemory.MemorySet.ATTACHED_THIS_TURN);
|
||||||
|
|
||||||
if (c == null && mandatory) {
|
if (c == null && mandatory) {
|
||||||
@@ -1372,7 +1374,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach general ai.
|
* Attach general ai.
|
||||||
*
|
*
|
||||||
* @param sa
|
* @param sa
|
||||||
* the sa
|
* the sa
|
||||||
* @param list
|
* @param list
|
||||||
@@ -1448,7 +1450,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains useful curse keyword.
|
* Contains useful curse keyword.
|
||||||
*
|
*
|
||||||
* @param keywords
|
* @param keywords
|
||||||
* the keywords
|
* the keywords
|
||||||
* @param card
|
* @param card
|
||||||
@@ -1467,7 +1469,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if is useful keyword.
|
* Checks if is useful keyword.
|
||||||
*
|
*
|
||||||
* @param keyword
|
* @param keyword
|
||||||
* the keyword
|
* the keyword
|
||||||
* @param card
|
* @param card
|
||||||
@@ -1478,7 +1480,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
private static boolean isUsefulAttachKeyword(final String keyword, final Card card, final SpellAbility sa, final int powerBonus) {
|
private static boolean isUsefulAttachKeyword(final String keyword, final Card card, final SpellAbility sa, final int powerBonus) {
|
||||||
final Player ai = sa.getActivatingPlayer();
|
final Player ai = sa.getActivatingPlayer();
|
||||||
final PhaseHandler ph = ai.getGame().getPhaseHandler();
|
final PhaseHandler ph = ai.getGame().getPhaseHandler();
|
||||||
|
|
||||||
if (!CardUtil.isStackingKeyword(keyword) && card.hasKeyword(keyword)) {
|
if (!CardUtil.isStackingKeyword(keyword) && card.hasKeyword(keyword)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1597,7 +1599,7 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if is useful curse keyword.
|
* Checks if is useful curse keyword.
|
||||||
*
|
*
|
||||||
* @param keyword
|
* @param keyword
|
||||||
* the keyword
|
* the keyword
|
||||||
* @param card
|
* @param card
|
||||||
@@ -1650,15 +1652,15 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if it is useful to execute the attach action given the current context.
|
* Checks if it is useful to execute the attach action given the current context.
|
||||||
*
|
*
|
||||||
* @param c
|
* @param c
|
||||||
* the card
|
* the card
|
||||||
* @param sa SpellAbility
|
* @param sa SpellAbility
|
||||||
* @return true, if the action is useful (beneficial) in the current minimal context (Card vs. Attach SpellAbility)
|
* @return true, if the action is useful (beneficial) in the current minimal context (Card vs. Attach SpellAbility)
|
||||||
*/
|
*/
|
||||||
private static boolean isUsefulAttachAction(Player ai, Card c, SpellAbility sa) {
|
private static boolean isUsefulAttachAction(Player ai, Card c, SpellAbility sa) {
|
||||||
if (c == null) {
|
if (c == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (sa.getHostCard() == null) {
|
if (sa.getHostCard() == null) {
|
||||||
// FIXME: Not sure what should the resolution be if a SpellAbility has no host card. This should
|
// FIXME: Not sure what should the resolution be if a SpellAbility has no host card. This should
|
||||||
@@ -1716,12 +1718,12 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable<Card> options, boolean isOptional, Player targetedPlayer) {
|
protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable<Card> options, boolean isOptional, Player targetedPlayer) {
|
||||||
return attachToCardAIPreferences(ai, sa, true);
|
return attachToCardAIPreferences(ai, sa, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable<Player> options) {
|
protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable<Player> options) {
|
||||||
return attachToPlayerAIPreferences(ai, sa, true);
|
return attachToPlayerAIPreferences(ai, sa, true);
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class ZoneExchangeAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
if (type.equals("Aura")) {
|
if (type.equals("Aura")) {
|
||||||
Card c = object1.getEnchantingCard();
|
Card c = object1.getEnchantingCard();
|
||||||
if (!c.canBeEnchantedBy(object2)) {
|
if (!c.canBeAttachedBy(object2)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ import forge.game.keyword.Keyword;
|
|||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.spellability.TargetRestrictions;
|
import forge.game.spellability.TargetRestrictions;
|
||||||
|
import forge.game.staticability.StaticAbility;
|
||||||
import forge.game.trigger.TriggerType;
|
import forge.game.trigger.TriggerType;
|
||||||
|
import forge.game.zone.ZoneType;
|
||||||
import forge.util.collect.FCollection;
|
import forge.util.collect.FCollection;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -372,11 +374,20 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
|||||||
|
|
||||||
public boolean canBeAttachedBy(final Card attach, boolean checkSBA) {
|
public boolean canBeAttachedBy(final Card attach, boolean checkSBA) {
|
||||||
// master mode
|
// master mode
|
||||||
if (!attach.isAttachment()) {
|
if (!attach.isAttachment() || attach.isCreature()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attach.isAura() && !canBeEnchantedBy(attach, checkSBA)) {
|
// CantTarget static abilities
|
||||||
|
for (final Card ca : getGame().getCardsIn(ZoneType.listValueOf("Battlefield,Command"))) {
|
||||||
|
for (final StaticAbility stAb : ca.getStaticAbilities()) {
|
||||||
|
if (stAb.applyAbility("CantAttach", attach, this)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attach.isAura() && !canBeEnchantedBy(attach)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (attach.isEquipment() && !canBeEquippedBy(attach)) {
|
if (attach.isEquipment() && !canBeEquippedBy(attach)) {
|
||||||
@@ -385,21 +396,24 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
|||||||
if (attach.isFortification() && !canBeFortifiedBy(attach)) {
|
if (attach.isFortification() && !canBeFortifiedBy(attach)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// true for all
|
||||||
|
if (hasProtectionFrom(attach, checkSBA)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canBeEquippedBy(final Card aura) {
|
protected boolean canBeEquippedBy(final Card aura) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canBeFortifiedBy(final Card aura) {
|
protected boolean canBeFortifiedBy(final Card aura) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canBeEnchantedBy(final Card aura, final boolean checkSBA) {
|
protected boolean canBeEnchantedBy(final Card aura) {
|
||||||
if (!aura.isAura()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SpellAbility sa = aura.getFirstAttachSpell();
|
SpellAbility sa = aura.getFirstAttachSpell();
|
||||||
TargetRestrictions tgt = null;
|
TargetRestrictions tgt = null;
|
||||||
@@ -407,8 +421,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
|||||||
tgt = sa.getTargetRestrictions();
|
tgt = sa.getTargetRestrictions();
|
||||||
}
|
}
|
||||||
|
|
||||||
return !(hasProtectionFrom(aura, checkSBA)
|
return !((tgt != null) && !isValid(tgt.getValidTgts(), aura.getController(), aura, sa));
|
||||||
|| ((tgt != null) && !isValid(tgt.getValidTgts(), aura.getController(), aura, sa)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasProtectionFrom(final Card source) {
|
public boolean hasProtectionFrom(final Card source) {
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ public class AttachEffect extends SpellAbilityEffect {
|
|||||||
// Although honestly, I'm not sure if the three of those could
|
// Although honestly, I'm not sure if the three of those could
|
||||||
// handle being scripted
|
// handle being scripted
|
||||||
// 303.4h: If the card can't be enchanted, the aura doesn't move
|
// 303.4h: If the card can't be enchanted, the aura doesn't move
|
||||||
if (c.canBeEnchantedBy(card)) {
|
if (c.canBeAttachedBy(card)) {
|
||||||
handleAura(card, c);
|
handleAura(card, c);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public class ZoneExchangeEffect extends SpellAbilityEffect {
|
|||||||
Card c = null;
|
Card c = null;
|
||||||
if (type != null && type.equals("Aura") && object1.getEnchantingCard() != null) {
|
if (type != null && type.equals("Aura") && object1.getEnchantingCard() != null) {
|
||||||
c = object1.getEnchantingCard();
|
c = object1.getEnchantingCard();
|
||||||
if (!c.canBeEnchantedBy(object2)) {
|
if (!c.canBeAttachedBy(object2)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5162,26 +5162,14 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
return !(hasKeyword("Other players can't gain control of CARDNAME.") && !getController().equals(newController));
|
return !(hasKeyword("Other players can't gain control of CARDNAME.") && !getController().equals(newController));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean canBeEnchantedBy(final Card aura) {
|
@Override
|
||||||
return canBeEnchantedBy(aura, false);
|
protected final boolean canBeEnchantedBy(final Card aura) {
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean canBeEnchantedBy(final Card aura, final boolean checkSBA) {
|
|
||||||
SpellAbility sa = aura.getFirstAttachSpell();
|
SpellAbility sa = aura.getFirstAttachSpell();
|
||||||
TargetRestrictions tgt = null;
|
TargetRestrictions tgt = null;
|
||||||
if (sa != null) {
|
if (sa != null) {
|
||||||
tgt = sa.getTargetRestrictions();
|
tgt = sa.getTargetRestrictions();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aura.isCreature()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// phase check there
|
|
||||||
if (isPhasedOut() && !aura.isPhasedOut()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tgt != null) {
|
if (tgt != null) {
|
||||||
boolean zoneValid = false;
|
boolean zoneValid = false;
|
||||||
// check the zone types
|
// check the zone types
|
||||||
@@ -5201,19 +5189,14 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return !(hasProtectionFrom(aura, checkSBA)
|
return !((hasKeyword("CARDNAME can't be enchanted in the future.") && !isEnchantedBy(aura))
|
||||||
|| (hasKeyword("CARDNAME can't be enchanted in the future.") && !isEnchantedBy(aura))
|
|
||||||
|| (hasKeyword("CARDNAME can't be enchanted.") && !aura.getName().equals("Anti-Magic Aura")
|
|| (hasKeyword("CARDNAME can't be enchanted.") && !aura.getName().equals("Anti-Magic Aura")
|
||||||
&& !(aura.getName().equals("Consecrate Land") && aura.isInZone(ZoneType.Battlefield))));
|
&& !(aura.getName().equals("Consecrate Land") && aura.isInZone(ZoneType.Battlefield))));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean canBeEquippedBy(final Card equip) {
|
@Override
|
||||||
if (!isCreature() || !isInPlay() || equip.isCreature()) {
|
protected final boolean canBeEquippedBy(final Card equip) {
|
||||||
return false;
|
if (!isCreature() || !isInPlay()) {
|
||||||
}
|
|
||||||
|
|
||||||
// phase check there
|
|
||||||
if (isPhasedOut() && !equip.isPhasedOut()) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5228,20 +5211,29 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return !(hasProtectionFrom(equip)
|
return true;
|
||||||
|| hasKeyword("CARDNAME can't be equipped."));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canBeFortifiedBy(final Card fort) {
|
@Override
|
||||||
if (!isLand() || !isInPlay() || fort.isCreature() || fort.isLand()) {
|
protected boolean canBeFortifiedBy(final Card fort) {
|
||||||
|
if (!isLand() || !isInPlay() || fort.isLand()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see forge.game.GameEntity#canBeAttachedBy(forge.game.card.Card, boolean)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean canBeAttachedBy(Card attach, boolean checkSBA) {
|
||||||
// phase check there
|
// phase check there
|
||||||
if (isPhasedOut() && !fort.isPhasedOut()) {
|
if (isPhasedOut() && !attach.isPhasedOut()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return !hasProtectionFrom(fort);
|
|
||||||
|
return super.canBeAttachedBy(attach, checkSBA);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FCollectionView<ReplacementEffect> getReplacementEffects() {
|
public FCollectionView<ReplacementEffect> getReplacementEffects() {
|
||||||
|
|||||||
@@ -216,20 +216,11 @@ public final class CardPredicates {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final Predicate<Card> canBeEnchantedBy(final Card aura) {
|
public static final Predicate<Card> canBeAttachedBy(final Card aura) {
|
||||||
return new Predicate<Card>() {
|
return new Predicate<Card>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(final Card c) {
|
public boolean apply(final Card c) {
|
||||||
return c.canBeEnchantedBy(aura);
|
return c.canBeAttachedBy(aura);
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final Predicate<Card> canBeEquippedBy(final Card eq) {
|
|
||||||
return new Predicate<Card>() {
|
|
||||||
@Override
|
|
||||||
public boolean apply(final Card c) {
|
|
||||||
return c.canBeEquippedBy(eq);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -508,11 +508,11 @@ public class CardProperty {
|
|||||||
final String restriction = property.substring(10);
|
final String restriction = property.substring(10);
|
||||||
if (restriction.equals("Remembered")) {
|
if (restriction.equals("Remembered")) {
|
||||||
for (final Object rem : source.getRemembered()) {
|
for (final Object rem : source.getRemembered()) {
|
||||||
if (!(rem instanceof Card) || !((Card) rem).canBeEnchantedBy(card))
|
if (!(rem instanceof Card) || !((Card) rem).canBeAttachedBy(card))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (restriction.equals("Source")) {
|
} else if (restriction.equals("Source")) {
|
||||||
if (!source.canBeEnchantedBy(card)) return false;
|
if (!source.canBeAttachedBy(card)) return false;
|
||||||
}
|
}
|
||||||
} else if (property.startsWith("CanBeEnchantedBy")) {
|
} else if (property.startsWith("CanBeEnchantedBy")) {
|
||||||
if (property.substring(16).equals("Targeted")) {
|
if (property.substring(16).equals("Targeted")) {
|
||||||
@@ -520,7 +520,7 @@ public class CardProperty {
|
|||||||
final SpellAbility saTargeting = sa.getSATargetingCard();
|
final SpellAbility saTargeting = sa.getSATargetingCard();
|
||||||
if (saTargeting != null) {
|
if (saTargeting != null) {
|
||||||
for (final Card c : saTargeting.getTargets().getTargetCards()) {
|
for (final Card c : saTargeting.getTargets().getTargetCards()) {
|
||||||
if (!card.canBeEnchantedBy(c)) {
|
if (!card.canBeAttachedBy(c)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -530,13 +530,13 @@ public class CardProperty {
|
|||||||
for (final Object rem : source.getRemembered()) {
|
for (final Object rem : source.getRemembered()) {
|
||||||
if (rem instanceof Card) {
|
if (rem instanceof Card) {
|
||||||
final Card c = (Card) rem;
|
final Card c = (Card) rem;
|
||||||
if (!card.canBeEnchantedBy(c)) {
|
if (!card.canBeAttachedBy(c)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!card.canBeEnchantedBy(source)) {
|
if (!card.canBeAttachedBy(source)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -566,8 +566,8 @@ public class CardProperty {
|
|||||||
if (!card.isFortifiedBy(source)) {
|
if (!card.isFortifiedBy(source)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.startsWith("CanBeEquippedBy")) {
|
} else if (property.startsWith("CanBeAttachedBy")) {
|
||||||
if (!card.canBeEquippedBy(source)) {
|
if (!card.canBeAttachedBy(source)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.startsWith("Equipped")) {
|
} else if (property.startsWith("Equipped")) {
|
||||||
|
|||||||
@@ -462,6 +462,8 @@ public class StaticAbility extends CardTraitBase implements Comparable<StaticAbi
|
|||||||
return StaticAbilityCantAttackBlock.applyCantAttackAbility(this, card, target);
|
return StaticAbilityCantAttackBlock.applyCantAttackAbility(this, card, target);
|
||||||
} else if (mode.equals("CantBlockBy") && target instanceof Card) {
|
} else if (mode.equals("CantBlockBy") && target instanceof Card) {
|
||||||
return StaticAbilityCantAttackBlock.applyCantBlockByAbility(this, card, (Card)target);
|
return StaticAbilityCantAttackBlock.applyCantBlockByAbility(this, card, (Card)target);
|
||||||
|
} else if (mode.equals("CantAttach")) {
|
||||||
|
return StaticAbilityCantAttach.applyCantAttachAbility(this, card, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package forge.game.staticability;
|
||||||
|
|
||||||
|
import forge.game.GameEntity;
|
||||||
|
import forge.game.card.Card;
|
||||||
|
|
||||||
|
public class StaticAbilityCantAttach {
|
||||||
|
|
||||||
|
public static boolean applyCantAttachAbility(final StaticAbility stAb, final Card card, final GameEntity target) {
|
||||||
|
final Card hostCard = stAb.getHostCard();
|
||||||
|
|
||||||
|
if (stAb.hasParam("ValidCard")
|
||||||
|
&& !card.isValid(stAb.getParam("ValidCard").split(","), hostCard.getController(), hostCard, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stAb.hasParam("Target")
|
||||||
|
&& !target.isValid(stAb.getParam("Target").split(","), hostCard.getController(), hostCard, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,6 @@ ManaCost:2 R
|
|||||||
Types:Creature Goblin Warrior
|
Types:Creature Goblin Warrior
|
||||||
PT:2/2
|
PT:2/2
|
||||||
K:First Strike
|
K:First Strike
|
||||||
K:CARDNAME can't be equipped.
|
S:Mode$ CantAttach | ValidCard$ Card.Equipment | Target$ Card.Self | Description$ CARDNAME can't be equipped.
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/goblin_brawler.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/goblin_brawler.jpg
|
||||||
Oracle:First strike\nGoblin Brawler can't be equipped.
|
Oracle:First strike\nGoblin Brawler can't be equipped.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Types:Artifact Equipment
|
|||||||
K:Equip:1
|
K:Equip:1
|
||||||
K:Flash
|
K:Flash
|
||||||
K:ETBReplacement:Other:ChooseC
|
K:ETBReplacement:Other:ChooseC
|
||||||
SVar:ChooseC:DB$ ChooseCard | Defined$ You | Choices$ Creature.YouCtrl+CanBeEquippedBy | Amount$ 1 | Mandatory$ True | SubAbility$ DBAttach | SpellDescription$ As CARDNAME enters the battlefield, choose a creature you control it could be attached to. If you do, it enters the battlefield attached to that creature.
|
SVar:ChooseC:DB$ ChooseCard | Defined$ You | Choices$ Creature.YouCtrl+CanBeAttachedBy | Amount$ 1 | Mandatory$ True | SubAbility$ DBAttach | SpellDescription$ As CARDNAME enters the battlefield, choose a creature you control it could be attached to. If you do, it enters the battlefield attached to that creature.
|
||||||
SVar:DBAttach:DB$ Attach | Object$ Self | Defined$ ChosenCard
|
SVar:DBAttach:DB$ Attach | Object$ Self | Defined$ ChosenCard
|
||||||
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 1 | AddToughness$ 1 | Description$ Equipped creature gets +1/+1.
|
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 1 | AddToughness$ 1 | Description$ Equipped creature gets +1/+1.
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/grifters_blade.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/grifters_blade.jpg
|
||||||
|
|||||||
Reference in New Issue
Block a user