mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
Merge pull request #185 from Card-Forge/attachSpellAbility
canEquip checks for SpellAbility
This commit is contained in:
@@ -1077,7 +1077,7 @@ public class ComputerUtil {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1135,7 +1135,7 @@ public abstract class GameState {
|
||||
Card attachedTo = idToCard.get(entry.getValue());
|
||||
Card attacher = entry.getKey();
|
||||
if (attacher.isAttachment()) {
|
||||
attacher.attachToEntity(attachedTo);
|
||||
attacher.attachToEntity(attachedTo, null, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1146,7 +1146,7 @@ public abstract class GameState {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -618,7 +618,7 @@ public class AttachAi extends SpellAbilityAi {
|
||||
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);
|
||||
@@ -1354,7 +1354,7 @@ public class AttachAi extends SpellAbilityAi {
|
||||
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()) {
|
||||
@@ -1627,7 +1627,6 @@ public class AttachAi extends SpellAbilityAi {
|
||||
* @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;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class ZoneExchangeAi extends SpellAbilityAi {
|
||||
}
|
||||
if (type.equals("Aura")) {
|
||||
Card c = object1.getEnchantingCard();
|
||||
if (!c.canBeAttached(object2)) {
|
||||
if (!c.canBeAttached(object2, sa)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ public class ForgeScript {
|
||||
} 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")) {
|
||||
|
||||
@@ -162,13 +162,13 @@ public class GameAction {
|
||||
// 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) {
|
||||
@@ -398,13 +398,13 @@ public class GameAction {
|
||||
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) {
|
||||
@@ -1515,7 +1515,7 @@ public class GameAction {
|
||||
|
||||
if (c.isAttachedToEntity()) {
|
||||
final GameEntity ge = c.getEntityAttachedTo();
|
||||
if (!ge.canBeAttached(c, true)) {
|
||||
if (!ge.canBeAttached(c, null, true)) {
|
||||
unAttachList.add(c);
|
||||
checkAgain = true;
|
||||
}
|
||||
@@ -2381,7 +2381,7 @@ public class GameAction {
|
||||
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 {
|
||||
@@ -2408,7 +2408,7 @@ public class GameAction {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,7 +341,7 @@ public final class GameActionUtil {
|
||||
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)) {
|
||||
|
||||
@@ -212,10 +212,10 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
@@ -226,7 +226,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
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)) {
|
||||
@@ -242,7 +242,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean canBeEquippedBy(final Card aura) {
|
||||
protected boolean canBeEquippedBy(final Card aura, SpellAbility sa) {
|
||||
/**
|
||||
* Equip only to Creatures which are cards
|
||||
*/
|
||||
|
||||
@@ -84,7 +84,7 @@ public class AttachEffect extends SpellAbilityEffect {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -100,7 +100,7 @@ public class AttachEffect extends SpellAbilityEffect {
|
||||
if (e != null)
|
||||
cardChoices.remove(e);
|
||||
}
|
||||
cardChoices = CardLists.filter(cardChoices, CardPredicates.canBeAttached(attachment));
|
||||
cardChoices = CardLists.filter(cardChoices, CardPredicates.canBeAttached(attachment, sa));
|
||||
}
|
||||
choices.addAll(cardChoices);
|
||||
}
|
||||
@@ -138,7 +138,7 @@ public class AttachEffect extends SpellAbilityEffect {
|
||||
// TODO add params for message
|
||||
continue;
|
||||
|
||||
attachment.attachToEntity(attachTo);
|
||||
attachment.attachToEntity(attachTo, sa);
|
||||
if (sa.hasParam("RememberAttached") && attachment.isAttachedToEntity(attachTo)) {
|
||||
source.addRemembered(attachment);
|
||||
}
|
||||
|
||||
@@ -615,7 +615,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
// 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();
|
||||
@@ -624,7 +624,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
|
||||
// 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;
|
||||
}
|
||||
@@ -636,7 +636,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
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;
|
||||
@@ -708,7 +708,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
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 {
|
||||
@@ -1287,7 +1287,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
// 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()));
|
||||
@@ -1297,7 +1297,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
|
||||
// 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;
|
||||
@@ -1311,7 +1311,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
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;
|
||||
@@ -1341,7 +1341,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ public abstract class TokenEffectBase extends SpellAbilityEffect {
|
||||
|
||||
boolean canAttach = lki.isAttachment();
|
||||
|
||||
if (canAttach && !ge.canBeAttached(lki)) {
|
||||
if (canAttach && !ge.canBeAttached(lki, sa)) {
|
||||
canAttach = false;
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ public abstract class TokenEffectBase extends SpellAbilityEffect {
|
||||
return false;
|
||||
}
|
||||
|
||||
tok.attachToEntity(ge);
|
||||
tok.attachToEntity(ge, sa);
|
||||
return true;
|
||||
}
|
||||
// not a GameEntity, cant be attach
|
||||
|
||||
@@ -81,14 +81,14 @@ public class ZoneExchangeEffect extends SpellAbilityEffect {
|
||||
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());
|
||||
|
||||
@@ -3440,22 +3440,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
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);
|
||||
}
|
||||
@@ -3511,11 +3495,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -6082,17 +6066,14 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
}
|
||||
|
||||
@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
|
||||
@@ -6104,13 +6085,13 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
* @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() {
|
||||
|
||||
@@ -251,11 +251,11 @@ public final class CardPredicates {
|
||||
};
|
||||
}
|
||||
|
||||
public static final Predicate<Card> canBeAttached(final Card aura) {
|
||||
public static final Predicate<Card> canBeAttached(final Card aura, final SpellAbility sa) {
|
||||
return new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.canBeAttached(aura);
|
||||
return c.canBeAttached(aura, sa);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -477,20 +477,20 @@ public class CardProperty {
|
||||
} else if (property.startsWith("CanEnchant")) {
|
||||
final String restriction = property.substring(10);
|
||||
if (restriction.equals("EquippedBy")) {
|
||||
if (!source.getEquipping().canBeAttached(card)) return false;
|
||||
if (!source.getEquipping().canBeAttached(card, null)) return false;
|
||||
}
|
||||
if (restriction.equals("Remembered")) {
|
||||
for (final Object rem : source.getRemembered()) {
|
||||
if (!(rem instanceof Card) || !((Card) rem).canBeAttached(card))
|
||||
if (!(rem instanceof Card) || !((Card) rem).canBeAttached(card, null))
|
||||
return false;
|
||||
}
|
||||
} else if (restriction.equals("Source")) {
|
||||
if (!source.canBeAttached(card)) return false;
|
||||
if (!source.canBeAttached(card, null)) return false;
|
||||
}
|
||||
} else if (property.startsWith("CanBeEnchantedBy")) {
|
||||
if (property.substring(16).equals("Targeted")) {
|
||||
for (final Card c : AbilityUtils.getDefinedCards(source, "Targeted", spellAbility)) {
|
||||
if (!card.canBeAttached(c)) {
|
||||
if (!card.canBeAttached(c, null)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -498,13 +498,13 @@ public class CardProperty {
|
||||
for (final Object rem : source.getRemembered()) {
|
||||
if (rem instanceof Card) {
|
||||
final Card c = (Card) rem;
|
||||
if (!card.canBeAttached(c)) {
|
||||
if (!card.canBeAttached(c, null)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!card.canBeAttached(source)) {
|
||||
if (!card.canBeAttached(source, null)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -530,7 +530,7 @@ public class CardProperty {
|
||||
return false;
|
||||
}
|
||||
} else if (property.startsWith("CanBeAttachedBy")) {
|
||||
if (!card.canBeAttached(source)) {
|
||||
if (!card.canBeAttached(source, null)) {
|
||||
return false;
|
||||
}
|
||||
} else if (property.startsWith("Fortified")) {
|
||||
|
||||
@@ -121,11 +121,11 @@ public final class PlayerPredicates {
|
||||
};
|
||||
}
|
||||
|
||||
public static final Predicate<Player> canBeAttached(final Card aura) {
|
||||
public static final Predicate<Player> canBeAttached(final Card aura, SpellAbility sa) {
|
||||
return new Predicate<Player>() {
|
||||
@Override
|
||||
public boolean apply(final Player p) {
|
||||
return p.canBeAttached(aura);
|
||||
return p.canBeAttached(aura, sa);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1035,6 +1035,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
return isAlternativeCost(AlternativeCost.Outlast);
|
||||
}
|
||||
|
||||
public boolean isEquip() {
|
||||
return hasParam("Equip");
|
||||
}
|
||||
|
||||
public boolean isBlessing() {
|
||||
return blessing;
|
||||
}
|
||||
|
||||
@@ -328,7 +328,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
}
|
||||
|
||||
// Log number of Equips
|
||||
if (sp.hasParam("Equip")) {
|
||||
if (sp.isEquip()) {
|
||||
activator.addEquipped();
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ public class GameSimulationTest extends SimulationTest {
|
||||
Card bear = addCard(bearCardName, p);
|
||||
bear.setSickness(false);
|
||||
Card cloak = addCard("Whispersilk Cloak", p);
|
||||
cloak.attachToEntity(bear);
|
||||
cloak.attachToEntity(bear, null);
|
||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
|
||||
game.getAction().checkStateEffects(true);
|
||||
AssertJUnit.assertEquals(1, bear.getAmountOfKeyword("Unblockable"));
|
||||
@@ -144,7 +144,7 @@ public class GameSimulationTest extends SimulationTest {
|
||||
Card bear = addCard(bearCardName, p);
|
||||
bear.setSickness(false);
|
||||
Card lifelink = addCard("Lifelink", p);
|
||||
lifelink.attachToEntity(bear);
|
||||
lifelink.attachToEntity(bear, null);
|
||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
|
||||
game.getAction().checkStateEffects(true);
|
||||
AssertJUnit.assertEquals(1, bear.getAmountOfKeyword("Lifelink"));
|
||||
@@ -700,7 +700,7 @@ public class GameSimulationTest extends SimulationTest {
|
||||
Card pridemate = addCard(pridemateName, p1);
|
||||
Card indestructibility = addCard(indestructibilityName, p1);
|
||||
|
||||
indestructibility.attachToEntity(pridemate);
|
||||
indestructibility.attachToEntity(pridemate, null);
|
||||
|
||||
Card ignition = addCardToZone(ignitionName, p1, ZoneType.Hand);
|
||||
SpellAbility ignitionSA = ignition.getFirstSpellAbility();
|
||||
@@ -816,7 +816,7 @@ public class GameSimulationTest extends SimulationTest {
|
||||
Card pridemate = addCard(pridemateName, p1);
|
||||
Card indestructibility = addCard(indestructibilityName, p1);
|
||||
|
||||
indestructibility.attachToEntity(pridemate);
|
||||
indestructibility.attachToEntity(pridemate, null);
|
||||
|
||||
Card ignition = addCardToZone(ignitionName, p1, ZoneType.Hand);
|
||||
SpellAbility ignitionSA = ignition.getFirstSpellAbility();
|
||||
@@ -1425,7 +1425,7 @@ public class GameSimulationTest extends SimulationTest {
|
||||
Card bear = addCard(bearCardName, p);
|
||||
bear.setSickness(false);
|
||||
Card lifelink = addCard("Lifelink", p);
|
||||
lifelink.attachToEntity(bear);
|
||||
lifelink.attachToEntity(bear, null);
|
||||
|
||||
AssertJUnit.assertTrue(bear.isEnchanted());
|
||||
AssertJUnit.assertTrue(bear.hasCardAttachment(lifelink));
|
||||
@@ -1466,7 +1466,7 @@ public class GameSimulationTest extends SimulationTest {
|
||||
final String curseName = "Cruel Reality";
|
||||
|
||||
Card curse = addCard(curseName, p);
|
||||
curse.attachToEntity(p);
|
||||
curse.attachToEntity(p, null);
|
||||
game.getAction().checkStateEffects(true);
|
||||
AssertJUnit.assertTrue(p.isEnchanted());
|
||||
AssertJUnit.assertTrue(p.hasCardAttachment(curse));
|
||||
@@ -1500,7 +1500,7 @@ public class GameSimulationTest extends SimulationTest {
|
||||
Card mountain = addCardToZone("Mountain", p, ZoneType.Battlefield);
|
||||
Card fortification = addCardToZone("Darksteel Garrison", p, ZoneType.Battlefield);
|
||||
|
||||
fortification.attachToEntity(mountain);
|
||||
fortification.attachToEntity(mountain, null);
|
||||
game.getAction().checkStateEffects(true);
|
||||
|
||||
AssertJUnit.assertTrue(fortification.isFortification());
|
||||
@@ -1535,7 +1535,7 @@ public class GameSimulationTest extends SimulationTest {
|
||||
Card dryad = addCardToZone("Dryad Arbor", p, ZoneType.Battlefield);
|
||||
Card fortification = addCardToZone("Darksteel Garrison", p, ZoneType.Battlefield);
|
||||
|
||||
fortification.attachToEntity(dryad);
|
||||
fortification.attachToEntity(dryad, null);
|
||||
game.getAction().checkStateEffects(true);
|
||||
|
||||
AssertJUnit.assertTrue(dryad.isFortified());
|
||||
@@ -1693,7 +1693,7 @@ public class GameSimulationTest extends SimulationTest {
|
||||
String indestructibilityName = "Indestructibility";
|
||||
Card indestructibility = addCard(indestructibilityName, p);
|
||||
|
||||
indestructibility.attachToEntity(teysa);
|
||||
indestructibility.attachToEntity(teysa, null);
|
||||
|
||||
// update Indestructible state
|
||||
game.getAction().checkStateEffects(true);
|
||||
@@ -1732,7 +1732,7 @@ public class GameSimulationTest extends SimulationTest {
|
||||
String indestructibilityName = "Indestructibility";
|
||||
Card indestructibility = addCard(indestructibilityName, p);
|
||||
|
||||
indestructibility.attachToEntity(gitrog);
|
||||
indestructibility.attachToEntity(gitrog, null);
|
||||
|
||||
// update Indestructible state
|
||||
game.getAction().checkStateEffects(true);
|
||||
@@ -2305,7 +2305,7 @@ public class GameSimulationTest extends SimulationTest {
|
||||
addCard(capridorName, p1);
|
||||
Card pridemate = addCard(pridemateName, p1);
|
||||
Card indestructibility = addCard(indestructibilityName, p1);
|
||||
indestructibility.attachToEntity(pridemate);
|
||||
indestructibility.attachToEntity(pridemate, null);
|
||||
addCard(bearName, p1);
|
||||
|
||||
Card alphaBrawl = addCardToZone(alphaBrawlName, p2, ZoneType.Hand);
|
||||
|
||||
@@ -40,141 +40,146 @@ public class GameWrapper {
|
||||
private final PlayerActions playerActions;
|
||||
private final GameLog gameLog;
|
||||
private Game game;
|
||||
|
||||
public GameWrapper( GameStateSpecification initialGameStateSpecification, PlayerActions playerActions ) {
|
||||
this( initialGameStateSpecification, playerActions, Arrays.asList( PlayerSpecification.PLAYER_1, PlayerSpecification.PLAYER_2 ) );
|
||||
|
||||
public GameWrapper(GameStateSpecification initialGameStateSpecification, PlayerActions playerActions) {
|
||||
this(initialGameStateSpecification, playerActions,
|
||||
Arrays.asList(PlayerSpecification.PLAYER_1, PlayerSpecification.PLAYER_2));
|
||||
}
|
||||
|
||||
public GameWrapper( GameStateSpecification initialGameStateSpecification, PlayerActions playerActions, List<PlayerSpecification> players ) {
|
||||
|
||||
public GameWrapper(GameStateSpecification initialGameStateSpecification, PlayerActions playerActions,
|
||||
List<PlayerSpecification> players) {
|
||||
this.initialGameStateSpecification = initialGameStateSpecification;
|
||||
this.playerActions = playerActions;
|
||||
this.players = players;
|
||||
|
||||
|
||||
gameLog = new GameLog();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This start method attempts to start from the specified game state.
|
||||
* That requires a bit of ugly hackery, possibly breaking after harmless refactorings or improvements to real code,
|
||||
* and always casting doubt upon the veracity of test results.
|
||||
* To somewhat minimize those concerns, starting with stuff on the stack and/or combat in progress is pretty much out of the question.
|
||||
* Note that if you use this option, regular startup is ignored (using player deck, shuffling, drawing hand, mulligan, ...)
|
||||
* This start method attempts to start from the specified game state. That
|
||||
* requires a bit of ugly hackery, possibly breaking after harmless refactorings
|
||||
* or improvements to real code, and always casting doubt upon the veracity of
|
||||
* test results. To somewhat minimize those concerns, starting with stuff on the
|
||||
* stack and/or combat in progress is pretty much out of the question. Note that
|
||||
* if you use this option, regular startup is ignored (using player deck,
|
||||
* shuffling, drawing hand, mulligan, ...)
|
||||
*/
|
||||
public void runGame() {
|
||||
List<RegisteredPlayer> registeredPlayers = new ArrayList<>();
|
||||
for( PlayerSpecification player : players ) {
|
||||
for (PlayerSpecification player : players) {
|
||||
RegisteredPlayer registeredPlayer = new RegisteredPlayer(new Deck(player.getName()));
|
||||
LobbyPlayerForTests lobbyPlayer = new LobbyPlayerForTests( player.getName(), playerActions );
|
||||
registeredPlayer.setPlayer( lobbyPlayer );
|
||||
registeredPlayers.add( registeredPlayer );
|
||||
LobbyPlayerForTests lobbyPlayer = new LobbyPlayerForTests(player.getName(), playerActions);
|
||||
registeredPlayer.setPlayer(lobbyPlayer);
|
||||
registeredPlayers.add(registeredPlayer);
|
||||
}
|
||||
|
||||
|
||||
GameRules rules = new GameRules(GameType.Constructed);
|
||||
rules.setPlayForAnte(FModel.getPreferences().getPrefBoolean(FPref.UI_ANTE));
|
||||
rules.setMatchAnteRarity(FModel.getPreferences().getPrefBoolean(FPref.UI_ANTE_MATCH_RARITY));
|
||||
rules.setMatchAnteRarity(FModel.getPreferences().getPrefBoolean(FPref.UI_ANTE_MATCH_RARITY));
|
||||
rules.setManaBurn(FModel.getPreferences().getPrefBoolean(FPref.UI_MANABURN));
|
||||
rules.setUseGrayText(FModel.getPreferences().getPrefBoolean(FPref.UI_GRAY_INACTIVE_TEXT));
|
||||
Match match = new Match(rules, registeredPlayers, "Test");
|
||||
game = match.createGame();
|
||||
|
||||
//GameNew.newGame( game, false, false ) does a bit of internal setup, then prepares libraries etc
|
||||
Trigger.resetIDs();
|
||||
TriggerHandler trigHandler = game.getTriggerHandler();
|
||||
trigHandler.clearDelayedTrigger();
|
||||
|
||||
//instead of preparing libraries the normal way, we'll distribute cards across the specified zones
|
||||
if( initialGameStateSpecification != null && !initialGameStateSpecification.getCards().isEmpty() ) {
|
||||
for( CardSpecification card : initialGameStateSpecification.getCards() ) {
|
||||
PaperCard paperCard = CardDatabaseHelper.getCard( card.getName() );
|
||||
|
||||
PlayerSpecification owner = card.getOwner();
|
||||
PlayerSpecification controller = card.getController();
|
||||
if( owner == null ) {
|
||||
owner = controller;
|
||||
}
|
||||
if( controller == null ) {
|
||||
controller = owner;
|
||||
}
|
||||
|
||||
if( owner == null ) {
|
||||
throw new IllegalStateException( "Cards must specify owner for game state specification" );
|
||||
}
|
||||
Player actualOwner = PlayerSpecificationHandler.INSTANCE.find( game, owner );
|
||||
if( controller == null ) {
|
||||
throw new IllegalStateException( "Cards must specify controller for game state specification" );
|
||||
}
|
||||
Player actualController = PlayerSpecificationHandler.INSTANCE.find( game, controller );
|
||||
|
||||
ZoneType zoneType = card.getZoneType();
|
||||
if( zoneType == null ) {
|
||||
throw new IllegalStateException( "Cards must specify zone for game state specification" );
|
||||
}
|
||||
|
||||
Card actualCard = Card.fromPaperCard( paperCard, actualOwner );
|
||||
actualController.getZone( zoneType ).add( actualCard );
|
||||
|
||||
if( card.getTarget() != null ) {
|
||||
Card target = CardSpecificationHandler.INSTANCE.find( game, card.getTarget() );
|
||||
if (actualCard.isAttachment()) {
|
||||
if (target.canBeAttached(actualCard)) {
|
||||
actualCard.attachToEntity(target);
|
||||
} else {
|
||||
throw new IllegalStateException( actualCard + " can't attach to " + target );
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException( "Don't know how to make " + actualCard + " target anything" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//may need to tweak players a bit too
|
||||
if( initialGameStateSpecification != null && !initialGameStateSpecification.getPlayerFacts().isEmpty() ) {
|
||||
for( final PlayerSpecification playerFact : initialGameStateSpecification.getPlayerFacts() ) {
|
||||
final PlayerSpecification basePlayerSpec = new PlayerSpecificationBuilder( playerFact.getName() ).build();
|
||||
Player player = PlayerSpecificationHandler.INSTANCE.find( game, basePlayerSpec );
|
||||
|
||||
if( playerFact.getLife() != null ) {
|
||||
player.setLife( playerFact.getLife(), null );
|
||||
}
|
||||
|
||||
if( playerFact.getPoison() != null ) {
|
||||
player.setPoisonCounters( playerFact.getPoison(), null );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//game.getAction().startGame( null ) determines starting player, draws starting hands, handles mulligans, and initiates the first turn
|
||||
//skip drawing initial hand and mulliganing
|
||||
game.setAge( GameStage.Play );
|
||||
game.getTriggerHandler().runTrigger(TriggerType.NewGame, AbilityKey.newMap(), false);
|
||||
|
||||
//first player in the list starts, no coin toss etc
|
||||
game.getPhaseHandler().startFirstTurn( game.getPlayers().get( 0 ) );
|
||||
game.fireEvent( new GameEventGameFinished() );
|
||||
// GameNew.newGame( game, false, false ) does a bit of internal setup, then
|
||||
// prepares libraries etc
|
||||
Trigger.resetIDs();
|
||||
TriggerHandler trigHandler = game.getTriggerHandler();
|
||||
trigHandler.clearDelayedTrigger();
|
||||
|
||||
// instead of preparing libraries the normal way, we'll distribute cards across
|
||||
// the specified zones
|
||||
if (initialGameStateSpecification != null && !initialGameStateSpecification.getCards().isEmpty()) {
|
||||
for (CardSpecification card : initialGameStateSpecification.getCards()) {
|
||||
PaperCard paperCard = CardDatabaseHelper.getCard(card.getName());
|
||||
|
||||
PlayerSpecification owner = card.getOwner();
|
||||
PlayerSpecification controller = card.getController();
|
||||
if (owner == null) {
|
||||
owner = controller;
|
||||
}
|
||||
if (controller == null) {
|
||||
controller = owner;
|
||||
}
|
||||
|
||||
if (owner == null) {
|
||||
throw new IllegalStateException("Cards must specify owner for game state specification");
|
||||
}
|
||||
Player actualOwner = PlayerSpecificationHandler.INSTANCE.find(game, owner);
|
||||
if (controller == null) {
|
||||
throw new IllegalStateException("Cards must specify controller for game state specification");
|
||||
}
|
||||
Player actualController = PlayerSpecificationHandler.INSTANCE.find(game, controller);
|
||||
|
||||
ZoneType zoneType = card.getZoneType();
|
||||
if (zoneType == null) {
|
||||
throw new IllegalStateException("Cards must specify zone for game state specification");
|
||||
}
|
||||
|
||||
Card actualCard = Card.fromPaperCard(paperCard, actualOwner);
|
||||
actualController.getZone(zoneType).add(actualCard);
|
||||
|
||||
if (card.getTarget() != null) {
|
||||
Card target = CardSpecificationHandler.INSTANCE.find(game, card.getTarget());
|
||||
if (actualCard.isAttachment()) {
|
||||
if (target.canBeAttached(actualCard, null)) {
|
||||
actualCard.attachToEntity(target, null);
|
||||
} else {
|
||||
throw new IllegalStateException(actualCard + " can't attach to " + target);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Don't know how to make " + actualCard + " target anything");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// may need to tweak players a bit too
|
||||
if (initialGameStateSpecification != null && !initialGameStateSpecification.getPlayerFacts().isEmpty()) {
|
||||
for (final PlayerSpecification playerFact : initialGameStateSpecification.getPlayerFacts()) {
|
||||
final PlayerSpecification basePlayerSpec = new PlayerSpecificationBuilder(playerFact.getName()).build();
|
||||
Player player = PlayerSpecificationHandler.INSTANCE.find(game, basePlayerSpec);
|
||||
|
||||
if (playerFact.getLife() != null) {
|
||||
player.setLife(playerFact.getLife(), null);
|
||||
}
|
||||
|
||||
if (playerFact.getPoison() != null) {
|
||||
player.setPoisonCounters(playerFact.getPoison(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// game.getAction().startGame( null ) determines starting player, draws starting
|
||||
// hands, handles mulligans, and initiates the first turn
|
||||
// skip drawing initial hand and mulliganing
|
||||
game.setAge(GameStage.Play);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.NewGame, AbilityKey.newMap(), false);
|
||||
|
||||
// first player in the list starts, no coin toss etc
|
||||
game.getPhaseHandler().startFirstTurn(game.getPlayers().get(0));
|
||||
game.fireEvent(new GameEventGameFinished());
|
||||
}
|
||||
|
||||
|
||||
public PlayerActions getPlayerActions() {
|
||||
return playerActions;
|
||||
}
|
||||
|
||||
|
||||
public Game getGame() {
|
||||
return game;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "Game log : \r\n" );
|
||||
List<GameLogEntry> gameLogEntries = gameLog.getLogEntries( GameLogEntryType.PHASE );
|
||||
Collections.reverse( gameLogEntries );
|
||||
for( GameLogEntry gameLogEntry : gameLogEntries ) {
|
||||
sb.append( gameLogEntry.toString() ).append( "\r\n" );
|
||||
|
||||
sb.append("Game log : \r\n");
|
||||
List<GameLogEntry> gameLogEntries = gameLog.getLogEntries(GameLogEntryType.PHASE);
|
||||
Collections.reverse(gameLogEntries);
|
||||
for (GameLogEntry gameLogEntry : gameLogEntries) {
|
||||
sb.append(gameLogEntry.toString()).append("\r\n");
|
||||
}
|
||||
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user