GameEntity: when attachment is phased out, treat as not attached

This commit is contained in:
Hans Mackowiak
2021-04-11 17:00:20 +02:00
parent 183209baa3
commit f6ee232d9e
8 changed files with 65 additions and 72 deletions

View File

@@ -41,14 +41,12 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.staticability.StaticAbility; import forge.game.staticability.StaticAbility;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.collect.FCollection;
public abstract class GameEntity extends GameObject implements IIdentifiable { public abstract class GameEntity extends GameObject implements IIdentifiable {
protected final int id; protected final int id;
private String name = ""; private String name = "";
private int preventNextDamage = 0; private int preventNextDamage = 0;
protected CardCollection attachedCards; protected CardCollection attachedCards = new CardCollection();
private Map<Card, Map<String, String>> preventionShieldsWithEffects = Maps.newTreeMap(); private Map<Card, Map<String, String>> preventionShieldsWithEffects = Maps.newTreeMap();
protected Map<CounterType, Integer> counters = Maps.newHashMap(); protected Map<CounterType, Integer> counters = Maps.newHashMap();
@@ -285,43 +283,36 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
public abstract boolean hasKeyword(final Keyword keyword); public abstract boolean hasKeyword(final Keyword keyword);
public final CardCollectionView getEnchantedBy() { public final CardCollectionView getEnchantedBy() {
if (attachedCards == null) {
return CardCollection.EMPTY;
}
// enchanted means attached by Aura // enchanted means attached by Aura
return CardLists.filter(attachedCards, CardPredicates.Presets.AURA); return CardLists.filter(getAttachedCards(), CardPredicates.Presets.AURA);
} }
// doesn't include phased out cards
public final CardCollectionView getAttachedCards() { public final CardCollectionView getAttachedCards() {
return CardCollection.getView(attachedCards); return CardLists.filter(attachedCards, CardPredicates.phasedIn());
}
// for view does include phased out cards
public final CardCollectionView getAllAttachedCards() {
return attachedCards;
} }
public final void setAttachedCards(final Iterable<Card> cards) { public final void setAttachedCards(final Iterable<Card> cards) {
if (cards == null) { attachedCards = new CardCollection(cards);
attachedCards = null; updateAttachedCards();
}
else {
attachedCards = new CardCollection(cards);
}
getView().updateAttachedCards(this);
} }
public final boolean hasCardAttachments() { public final boolean hasCardAttachments() {
return FCollection.hasElements(attachedCards); return !getAttachedCards().isEmpty();
} }
public final boolean isEnchanted() { public final boolean isEnchanted() {
if (attachedCards == null) {
return false;
}
// enchanted means attached by Aura // enchanted means attached by Aura
return Iterables.any(attachedCards, CardPredicates.Presets.AURA); return Iterables.any(getAttachedCards(), CardPredicates.Presets.AURA);
} }
public final boolean hasCardAttachment(Card c) { public final boolean hasCardAttachment(Card c) {
return FCollection.hasElement(attachedCards, c); return getAttachedCards().contains(c);
} }
public final boolean isEnchantedBy(Card c) { public final boolean isEnchantedBy(Card c) {
// Rule 303.4k Even if c is no Aura it still counts // Rule 303.4k Even if c is no Aura it still counts
@@ -329,9 +320,6 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
} }
public final boolean hasCardAttachment(final String cardName) { public final boolean hasCardAttachment(final String cardName) {
if (attachedCards == null) {
return false;
}
return CardLists.count(getAttachedCards(), CardPredicates.nameEquals(cardName)) > 0; return CardLists.count(getAttachedCards(), CardPredicates.nameEquals(cardName)) > 0;
} }
public final boolean isEnchantedBy(final String cardName) { public final boolean isEnchantedBy(final String cardName) {
@@ -344,12 +332,8 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
* @param Card c * @param Card c
*/ */
public final void addAttachedCard(final Card c) { public final void addAttachedCard(final Card c) {
if (attachedCards == null) {
attachedCards = new CardCollection();
}
if (attachedCards.add(c)) { if (attachedCards.add(c)) {
getView().updateAttachedCards(this); updateAttachedCards();
getGame().fireEvent(new GameEventCardAttachment(c, null, this)); getGame().fireEvent(new GameEventCardAttachment(c, null, this));
} }
} }
@@ -359,17 +343,16 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
* @param Card c * @param Card c
*/ */
public final void removeAttachedCard(final Card c) { public final void removeAttachedCard(final Card c) {
if (attachedCards == null) { return; }
if (attachedCards.remove(c)) { if (attachedCards.remove(c)) {
if (attachedCards.isEmpty()) { updateAttachedCards();
attachedCards = null;
}
getView().updateAttachedCards(this);
getGame().fireEvent(new GameEventCardAttachment(c, this, null)); getGame().fireEvent(new GameEventCardAttachment(c, this, null));
} }
} }
public final void updateAttachedCards() {
getView().updateAttachedCards(this);
}
public final void unAttachAllCards() { public final void unAttachAllCards() {
for (Card c : Lists.newArrayList(getAttachedCards())) { for (Card c : Lists.newArrayList(getAttachedCards())) {
c.unattachFromEntity(this); c.unattachFromEntity(this);

View File

@@ -1,5 +1,6 @@
package forge.game; package forge.game;
import forge.game.card.CardCollectionView;
import forge.game.card.CardView; import forge.game.card.CardView;
import forge.trackable.TrackableCollection; import forge.trackable.TrackableCollection;
import forge.trackable.TrackableObject; import forge.trackable.TrackableObject;
@@ -54,6 +55,12 @@ public abstract class GameEntityView extends TrackableObject {
public boolean hasCardAttachments() { public boolean hasCardAttachments() {
return getAttachedCards() != null; return getAttachedCards() != null;
} }
public Iterable<CardView> getAllAttachedCards() {
return get(TrackableProperty.AllAttachedCards);
}
public boolean hasAnyCardAttachments() {
return getAllAttachedCards() != null;
}
protected void updateAttachedCards(GameEntity e) { protected void updateAttachedCards(GameEntity e) {
if (e.hasCardAttachments()) { if (e.hasCardAttachments()) {
@@ -62,5 +69,11 @@ public abstract class GameEntityView extends TrackableObject {
else { else {
set(TrackableProperty.AttachedCards, null); set(TrackableProperty.AttachedCards, null);
} }
CardCollectionView all = e.getAllAttachedCards();
if (all.isEmpty()) {
set(TrackableProperty.AllAttachedCards, null);
} else {
set(TrackableProperty.AllAttachedCards, CardView.getCollection(all));
}
} }
} }

View File

@@ -3226,19 +3226,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
} }
public final CardCollectionView getEquippedBy() { public final CardCollectionView getEquippedBy() {
if (this.attachedCards == null) { return CardLists.filter(getAttachedCards(), CardPredicates.Presets.EQUIPMENT);
return CardCollection.EMPTY;
}
return CardLists.filter(attachedCards, CardPredicates.Presets.EQUIPMENT);
} }
public final boolean isEquipped() { public final boolean isEquipped() {
if (this.attachedCards == null) { return Iterables.any(getAttachedCards(), CardPredicates.Presets.EQUIPMENT);
return false;
}
return Iterables.any(attachedCards, CardPredicates.Presets.EQUIPMENT);
} }
public final boolean isEquippedBy(Card c) { public final boolean isEquippedBy(Card c) {
return this.hasCardAttachment(c); return this.hasCardAttachment(c);
@@ -3248,19 +3240,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
} }
public final CardCollectionView getFortifiedBy() { public final CardCollectionView getFortifiedBy() {
if (this.attachedCards == null) { return CardLists.filter(getAttachedCards(), CardPredicates.Presets.FORTIFICATION);
return CardCollection.EMPTY;
}
return CardLists.filter(attachedCards, CardPredicates.Presets.FORTIFICATION);
} }
public final boolean isFortified() { public final boolean isFortified() {
if (this.attachedCards == null) { return Iterables.any(getAttachedCards(), CardPredicates.Presets.FORTIFICATION);
return false;
}
return Iterables.any(attachedCards, CardPredicates.Presets.FORTIFICATION);
} }
public final boolean isFortifiedBy(Card c) { public final boolean isFortifiedBy(Card c) {
// 301.5e + 301.6 // 301.5e + 301.6
@@ -4624,6 +4608,12 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
} }
} }
// update the game entity it was attached to
GameEntity ge = this.getEntityAttachedTo();
if (ge != null) {
ge.updateAttachedCards();
}
getGame().fireEvent(new GameEventCardPhased(this, isPhasedOut())); getGame().fireEvent(new GameEventCardPhased(this, isPhasedOut()));
} }

View File

@@ -479,6 +479,16 @@ public final class CardPredicates {
}; };
} }
public static final Predicate<Card> phasedIn() {
return new Predicate<Card>() {
@Override
public boolean apply(final Card c)
{
return !c.isPhasedOut();
}
};
}
public static class Presets { public static class Presets {
/** /**

View File

@@ -3426,11 +3426,7 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
public final boolean isCursed() { public final boolean isCursed() {
if (this.attachedCards == null) { return CardLists.count(getAttachedCards(), CardPredicates.Presets.CURSE) > 0;
return false;
}
return CardLists.count(attachedCards, CardPredicates.Presets.CURSE) > 0;
} }
public boolean canDiscardBy(SpellAbility sa) { public boolean canDiscardBy(SpellAbility sa) {

View File

@@ -14,6 +14,7 @@ public enum TrackableProperty {
Text(TrackableTypes.StringType), Text(TrackableTypes.StringType),
PreventNextDamage(TrackableTypes.IntegerType), PreventNextDamage(TrackableTypes.IntegerType),
AttachedCards(TrackableTypes.CardViewCollectionType), AttachedCards(TrackableTypes.CardViewCollectionType),
AllAttachedCards(TrackableTypes.CardViewCollectionType),
Counters(TrackableTypes.CounterMapType), Counters(TrackableTypes.CounterMapType),
CurrentPlane(TrackableTypes.StringType), CurrentPlane(TrackableTypes.StringType),
PlanarPlayer(TrackableTypes.PlayerViewType), PlanarPlayer(TrackableTypes.PlayerViewType),

View File

@@ -688,8 +688,8 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
} }
toPanel.getAttachedPanels().clear(); toPanel.getAttachedPanels().clear();
if (card.hasCardAttachments()) { if (card.hasAnyCardAttachments()) {
final Iterable<CardView> enchants = card.getAttachedCards(); final Iterable<CardView> enchants = card.getAllAttachedCards();
for (final CardView e : enchants) { for (final CardView e : enchants) {
final CardPanel cardE = getCardPanel(e.getId()); final CardPanel cardE = getCardPanel(e.getId());
if (cardE != null) { if (cardE != null) {

View File

@@ -286,8 +286,8 @@ public abstract class VCardDisplayArea extends VDisplayArea implements ActivateH
attachedPanels.clear(); attachedPanels.clear();
if (card.hasCardAttachments()) { if (card.hasAnyCardAttachments()) {
final Iterable<CardView> enchants = card.getAttachedCards(); final Iterable<CardView> enchants = card.getAllAttachedCards();
for (final CardView e : enchants) { for (final CardView e : enchants) {
final CardAreaPanel cardE = CardAreaPanel.get(e); final CardAreaPanel cardE = CardAreaPanel.get(e);
if (cardE != null) { if (cardE != null) {