Skip to content

Commit

Permalink
canEquip checks for SpellAbility
Browse files Browse the repository at this point in the history
  • Loading branch information
Hanmac committed May 1, 2022
1 parent 7146468 commit 99c1076
Show file tree
Hide file tree
Showing 20 changed files with 187 additions and 198 deletions.
2 changes: 1 addition & 1 deletion forge-ai/src/main/java/forge/ai/ComputerUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,7 @@ public static boolean castPermanentInMain1(final Player ai, final SpellAbility s
playNow = false;
break;
}
if (!playNow && c.isCreature() && ComputerUtilCombat.canAttackNextTurn(c) && c.canBeAttached(card)) {
if (!playNow && c.isCreature() && ComputerUtilCombat.canAttackNextTurn(c) && c.canBeAttached(card, null)) {
playNow = true;
}
}
Expand Down
4 changes: 2 additions & 2 deletions forge-ai/src/main/java/forge/ai/GameState.java
Original file line number Diff line number Diff line change
Expand Up @@ -1135,7 +1135,7 @@ private void handleCardAttachments() {
Card attachedTo = idToCard.get(entry.getValue());
Card attacher = entry.getKey();
if (attacher.isAttachment()) {
attacher.attachToEntity(attachedTo);
attacher.attachToEntity(attachedTo, null, true);
}
}

Expand All @@ -1146,7 +1146,7 @@ private void handleCardAttachments() {
Game game = attacher.getGame();
Player attachedTo = entry.getValue() == TARGET_AI ? game.getPlayers().get(1) : game.getPlayers().get(0);

attacher.attachToEntity(attachedTo);
attacher.attachToEntity(attachedTo, null);
}
}

Expand Down
5 changes: 2 additions & 3 deletions forge-ai/src/main/java/forge/ai/ability/AttachAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ public boolean apply(final Card c) {
CardCollection preList = new CardCollection(lki);
preList.add(attachSourceLki);
c.getGame().getAction().checkStaticAbilities(false, Sets.newHashSet(preList), preList);
boolean result = lki.canBeAttached(attachSourceLki);
boolean result = lki.canBeAttached(attachSourceLki, null);

//reset static abilities
c.getGame().getAction().checkStaticAbilities(false);
Expand Down Expand Up @@ -1354,7 +1354,7 @@ public boolean apply(final Card card) {
if (tgt == null) {
list = AbilityUtils.getDefinedCards(attachSource, sa.getParam("Defined"), sa);
} else {
list = CardLists.filter(CardUtil.getValidCardsToTarget(tgt, sa), CardPredicates.canBeAttached(attachSource));
list = CardLists.filter(CardUtil.getValidCardsToTarget(tgt, sa), CardPredicates.canBeAttached(attachSource, sa));
}

if (list.isEmpty()) {
Expand Down Expand Up @@ -1627,7 +1627,6 @@ private static boolean isUsefulAttachKeyword(final String keyword, final Card ca
* @return true, if is useful keyword
*/
private static boolean isUsefulCurseKeyword(final String keyword, final Card card, final SpellAbility sa) {
final Player ai = sa.getActivatingPlayer();
if (!CardUtil.isStackingKeyword(keyword) && card.hasKeyword(keyword)) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ protected boolean canPlayAI(Player ai, final SpellAbility sa) {
}
if (type.equals("Aura")) {
Card c = object1.getEnchantingCard();
if (!c.canBeAttached(object2)) {
if (!c.canBeAttached(object2, sa)) {
return false;
}
}
Expand Down
2 changes: 1 addition & 1 deletion forge-game/src/main/java/forge/game/ForgeScript.java
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public static boolean spellAbilityHasProperty(SpellAbility sa, String property,
} else if (property.equals("Modular")) {
return sa.hasParam("Modular");
} else if (property.equals("Equip")) {
return sa.hasParam("Equip");
return sa.isEquip();
} else if (property.equals("Boast")) {
return sa.isBoast();
} else if (property.equals("Mutate")) {
Expand Down
18 changes: 9 additions & 9 deletions forge-game/src/main/java/forge/game/GameAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -162,13 +162,13 @@ private Card changeZone(final Zone zoneFrom, Zone zoneTo, final Card c, Integer
// need to check before it enters
if (c.isAura() && !c.isAttachedToEntity() && toBattlefield && (zoneFrom == null || !zoneFrom.is(ZoneType.Stack))) {
boolean found = false;
if (Iterables.any(game.getPlayers(), PlayerPredicates.canBeAttached(c))) {
if (Iterables.any(game.getPlayers(), PlayerPredicates.canBeAttached(c, null))) {
found = true;
}
else if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateBattlefield), CardPredicates.canBeAttached(c))) {
else if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateBattlefield), CardPredicates.canBeAttached(c, null))) {
found = true;
}
else if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateGraveyard), CardPredicates.canBeAttached(c))) {
else if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateGraveyard), CardPredicates.canBeAttached(c, null))) {
found = true;
}
if (!found) {
Expand Down Expand Up @@ -398,13 +398,13 @@ else if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateGrave
if (copied.isAura() && !copied.isAttachedToEntity() && toBattlefield) {
if (zoneFrom != null && zoneFrom.is(ZoneType.Stack) && game.getStack().isResolving(c)) {
boolean found = false;
if (Iterables.any(game.getPlayers(), PlayerPredicates.canBeAttached(copied))) {
if (Iterables.any(game.getPlayers(), PlayerPredicates.canBeAttached(copied, null))) {
found = true;
}
if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateBattlefield), CardPredicates.canBeAttached(copied))) {
if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateBattlefield), CardPredicates.canBeAttached(copied, null))) {
found = true;
}
if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateGraveyard), CardPredicates.canBeAttached(copied))) {
if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateGraveyard), CardPredicates.canBeAttached(copied, null))) {
found = true;
}
if (!found) {
Expand Down Expand Up @@ -1515,7 +1515,7 @@ private boolean stateBasedAction704_attach(Card c, CardCollection unAttachList)

if (c.isAttachedToEntity()) {
final GameEntity ge = c.getEntityAttachedTo();
if (!ge.canBeAttached(c, true)) {
if (!ge.canBeAttached(c, null, true)) {
unAttachList.add(c);
checkAgain = true;
}
Expand Down Expand Up @@ -2381,7 +2381,7 @@ public static boolean attachAuraOnIndirectEnterBattlefield(final Card source, Ma
final Player pa = p.getController().chooseSingleEntityForEffect(players, aura,
Localizer.getInstance().getMessage("lblSelectAPlayerAttachSourceTo", CardTranslation.getTranslatedName(source.getName())), null);
if (pa != null) {
source.attachToEntity(pa);
source.attachToEntity(pa, null);
return true;
}
} else {
Expand All @@ -2408,7 +2408,7 @@ public static boolean attachAuraOnIndirectEnterBattlefield(final Card source, Ma
final Card o = p.getController().chooseSingleEntityForEffect(list, aura,
Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", CardTranslation.getTranslatedName(source.getName())), null);
if (o != null) {
source.attachToEntity(game.getCardState(o), true);
source.attachToEntity(game.getCardState(o), null, true);
return true;
}
}
Expand Down
2 changes: 1 addition & 1 deletion forge-game/src/main/java/forge/game/GameActionUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ public static final List<SpellAbility> getAlternativeCosts(final SpellAbility sa
alternatives.add(newSA);
}
}
if (sa.hasParam("Equip") && activator.hasKeyword("You may pay 0 rather than pay equip costs.")) {
if (sa.isEquip() && activator.hasKeyword("You may pay 0 rather than pay equip costs.")) {
for (final KeywordInterface inst : source.getKeywords()) {
// need to find the correct Keyword from which this Ability is from
if (!inst.getAbilities().contains(sa)) {
Expand Down
10 changes: 5 additions & 5 deletions forge-game/src/main/java/forge/game/GameEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,10 @@ public final void unAttachAllCards() {
}
}

public boolean canBeAttached(final Card attach) {
return canBeAttached(attach, false);
public boolean canBeAttached(final Card attach, SpellAbility sa) {
return canBeAttached(attach, sa, false);
}
public boolean canBeAttached(final Card attach, boolean checkSBA) {
public boolean canBeAttached(final Card attach, SpellAbility sa, boolean checkSBA) {
// master mode
if (!attach.isAttachment() || (attach.isCreature() && !attach.hasKeyword(Keyword.RECONFIGURE))
|| equals(attach)) {
Expand All @@ -226,7 +226,7 @@ public boolean canBeAttached(final Card attach, boolean checkSBA) {
if (attach.isAura() && !canBeEnchantedBy(attach)) {
return false;
}
if (attach.isEquipment() && !canBeEquippedBy(attach)) {
if (attach.isEquipment() && !canBeEquippedBy(attach, sa)) {
return false;
}
if (attach.isFortification() && !canBeFortifiedBy(attach)) {
Expand All @@ -242,7 +242,7 @@ public boolean canBeAttached(final Card attach, boolean checkSBA) {
return true;
}

protected boolean canBeEquippedBy(final Card aura) {
protected boolean canBeEquippedBy(final Card aura, SpellAbility sa) {
/**
* Equip only to Creatures which are cards
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public void resolve(SpellAbility sa) {
choices = AbilityUtils.getDefinedEntities(source, sa.getParam("PlayerChoices"), sa);
for (final Card attachment : attachments) {
for (GameEntity g : choices) {
if (!g.canBeAttached(attachment)) {
if (!g.canBeAttached(attachment, sa)) {
choices.remove(g);
}
}
Expand All @@ -100,7 +100,7 @@ public void resolve(SpellAbility sa) {
if (e != null)
cardChoices.remove(e);
}
cardChoices = CardLists.filter(cardChoices, CardPredicates.canBeAttached(attachment));
cardChoices = CardLists.filter(cardChoices, CardPredicates.canBeAttached(attachment, sa));
}
choices.addAll(cardChoices);
}
Expand Down Expand Up @@ -138,7 +138,7 @@ public void resolve(SpellAbility sa) {
// TODO add params for message
continue;

attachment.attachToEntity(attachTo);
attachment.attachToEntity(attachTo, sa);
if (sa.hasParam("RememberAttached") && attachment.isAttachedToEntity(attachTo)) {
source.addRemembered(attachment);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ private void changeKnownOriginResolve(final SpellAbility sa) {
// only valid choices are when they could be attached
// TODO for multiple Auras entering attached this way, need to use LKI info
if (!list.isEmpty()) {
list = CardLists.filter(list, CardPredicates.canBeAttached(gameCard));
list = CardLists.filter(list, CardPredicates.canBeAttached(gameCard, sa));
}
if (!list.isEmpty()) {
Map<String, Object> params = Maps.newHashMap();
Expand All @@ -624,7 +624,7 @@ private void changeKnownOriginResolve(final SpellAbility sa) {

// TODO can't attach later or moveToPlay would attach indirectly
// bypass canBeAttached to skip Protection checks when trying to attach multiple auras that would grant protection
gameCard.attachToEntity(game.getCardState(attachedTo), true);
gameCard.attachToEntity(game.getCardState(attachedTo), sa, true);
} else { // When it should enter the battlefield attached to an illegal permanent it fails
continue;
}
Expand All @@ -636,7 +636,7 @@ private void changeKnownOriginResolve(final SpellAbility sa) {
Map<String, Object> params = Maps.newHashMap();
params.put("Attach", gameCard);
Player attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectAPlayerAttachSourceTo", gameCard.toString()), params);
gameCard.attachToEntity(attachedTo);
gameCard.attachToEntity(attachedTo, sa);
}
else { // When it should enter the battlefield attached to an illegal player it fails
continue;
Expand Down Expand Up @@ -708,7 +708,7 @@ private void changeKnownOriginResolve(final SpellAbility sa) {
Map<String, Object> params = Maps.newHashMap();
params.put("Attach", gameCard);
Card attachedTo = chooser.getController().chooseSingleEntityForEffect(list, sa, title, params);
movedCard.attachToEntity(attachedTo);
movedCard.attachToEntity(attachedTo, sa);
}
}
} else {
Expand Down Expand Up @@ -1287,7 +1287,7 @@ else if (destination.equals(ZoneType.Battlefield)) {
// only valid choices are when they could be attached
// TODO for multiple Auras entering attached this way, need to use LKI info
if (!list.isEmpty()) {
list = CardLists.filter(list, CardPredicates.canBeAttached(c));
list = CardLists.filter(list, CardPredicates.canBeAttached(c, sa));
}
if (!list.isEmpty()) {
String title = Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", CardTranslation.getTranslatedName(c.getName()));
Expand All @@ -1297,7 +1297,7 @@ else if (destination.equals(ZoneType.Battlefield)) {

// TODO can't attach later or moveToPlay would attach indirectly
// bypass canBeAttached to skip Protection checks when trying to attach multiple auras that would grant protection
c.attachToEntity(game.getCardState(attachedTo), true);
c.attachToEntity(game.getCardState(attachedTo), sa, true);
}
else { // When it should enter the battlefield attached to an illegal permanent it fails
continue;
Expand All @@ -1311,7 +1311,7 @@ else if (destination.equals(ZoneType.Battlefield)) {
Map<String, Object> params = Maps.newHashMap();
params.put("Attach", c);
Player attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, title, params);
c.attachToEntity(attachedTo);
c.attachToEntity(attachedTo, sa);
}
else { // When it should enter the battlefield attached to an illegal permanent it fails
continue;
Expand Down Expand Up @@ -1341,7 +1341,7 @@ else if (destination.equals(ZoneType.Battlefield)) {
Map<String, Object> params = Maps.newHashMap();
params.put("Attach", movedCard);
Card attachedTo = decider.getController().chooseSingleEntityForEffect(list, sa, title, params);
movedCard.attachToEntity(attachedTo);
movedCard.attachToEntity(attachedTo, sa);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ private boolean attachTokenTo(Card tok, SpellAbility sa) {

boolean canAttach = lki.isAttachment();

if (canAttach && !ge.canBeAttached(lki)) {
if (canAttach && !ge.canBeAttached(lki, sa)) {
canAttach = false;
}

Expand All @@ -254,7 +254,7 @@ private boolean attachTokenTo(Card tok, SpellAbility sa) {
return false;
}

tok.attachToEntity(ge);
tok.attachToEntity(ge, sa);
return true;
}
// not a GameEntity, cant be attach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,14 @@ public void resolve(SpellAbility sa) {
Card c = null;
if (type != null && type.equals("Aura") && object1.getEnchantingCard() != null) {
c = object1.getEnchantingCard();
if (!c.canBeAttached(object2)) {
if (!c.canBeAttached(object2, sa)) {
return;
}
}
// Enchant first
if (c != null) {
object1.unattachFromEntity(c);
object2.attachToEntity(c);
object2.attachToEntity(c, sa);
}
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield());
Expand Down
45 changes: 13 additions & 32 deletions forge-game/src/main/java/forge/game/card/Card.java
Original file line number Diff line number Diff line change
Expand Up @@ -3440,22 +3440,6 @@ public final boolean isFortifying() {
return this.isAttachedToEntity();
}

public final void equipCard(final Card c) {
if (!isEquipment()) {
return;
}

this.attachToEntity(c);
}

public final void fortifyCard(final Card c) {
if (!isFortification()) {
return;
}

this.attachToEntity(c);
}

public final void unEquipCard(final Card c) { // equipment.unEquipCard(equippedCard);
this.unattachFromEntity(c);
}
Expand Down Expand Up @@ -3511,11 +3495,11 @@ public final boolean isEnchantingCard() {
return getEnchantingCard() != null;
}

public final void attachToEntity(final GameEntity entity) {
attachToEntity(entity, false);
public final void attachToEntity(final GameEntity entity, SpellAbility sa) {
attachToEntity(entity, sa, false);
}
public final void attachToEntity(final GameEntity entity, boolean overwrite) {
if (!overwrite && !entity.canBeAttached(this)) {
public final void attachToEntity(final GameEntity entity, SpellAbility sa, boolean overwrite) {
if (!overwrite && !entity.canBeAttached(this, sa)) {
return;
}

Expand Down Expand Up @@ -6082,17 +6066,14 @@ protected final boolean canBeEnchantedBy(final Card aura) {
}

@Override
protected final boolean canBeEquippedBy(final Card equip) {
if (isCreature() && isInPlay()) {
return true;
} else if (isPlaneswalker() && isInPlay()) {
for (KeywordInterface inst : equip.getKeywords(Keyword.EQUIP)) {
if (inst.getOriginal().contains("planeswalker")) {
return true;
}
}
protected final boolean canBeEquippedBy(final Card equip, SpellAbility sa) {
if (!isInPlay()) {
return false;
}
return false;
if (sa != null && sa.isEquip()) {
return isValid(sa.getTargetRestrictions().getValidTgts(), sa.getActivatingPlayer(), equip, sa);
}
return isCreature();
}

@Override
Expand All @@ -6104,13 +6085,13 @@ protected boolean canBeFortifiedBy(final Card fort) {
* @see forge.game.GameEntity#canBeAttached(forge.game.card.Card, boolean)
*/
@Override
public boolean canBeAttached(Card attach, boolean checkSBA) {
public boolean canBeAttached(Card attach, SpellAbility sa, boolean checkSBA) {
// phase check there
if (isPhasedOut() && !attach.isPhasedOut()) {
return false;
}

return super.canBeAttached(attach, checkSBA);
return super.canBeAttached(attach, sa, checkSBA);
}

public FCollectionView<ReplacementEffect> getReplacementEffects() {
Expand Down
Loading

0 comments on commit 99c1076

Please sign in to comment.