mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
Merge pull request #382 from Northmoc/nccParty
NCC: Life of the Party and support
This commit is contained in:
@@ -33,7 +33,6 @@ import forge.util.Aggregates;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.PredicateString.StringOp;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.collect.FCollectionView;
|
||||
|
||||
public class CopyPermanentEffect extends TokenEffectBase {
|
||||
|
||||
@@ -105,112 +104,6 @@ public class CopyPermanentEffect extends TokenEffectBase {
|
||||
final Card host = sa.getHostCard();
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
final Game game = host.getGame();
|
||||
|
||||
if (sa.hasParam("Optional") && !activator.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblCopyPermanentConfirm"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int numCopies = sa.hasParam("NumCopies") ? AbilityUtils.calculateAmount(host, sa.getParam("NumCopies"), sa) : 1;
|
||||
|
||||
Player controller = null;
|
||||
if (sa.hasParam("Controller")) {
|
||||
final FCollectionView<Player> defined = AbilityUtils.getDefinedPlayers(host, sa.getParam("Controller"), sa);
|
||||
if (!defined.isEmpty()) {
|
||||
controller = defined.getFirst();
|
||||
}
|
||||
}
|
||||
if (controller == null) {
|
||||
controller = activator;
|
||||
}
|
||||
|
||||
List<Card> tgtCards = Lists.newArrayList();
|
||||
|
||||
if (sa.hasParam("ValidSupportedCopy")) {
|
||||
List<PaperCard> cards = Lists.newArrayList(StaticData.instance().getCommonCards().getUniqueCards());
|
||||
String valid = sa.getParam("ValidSupportedCopy");
|
||||
if (valid.contains("X")) {
|
||||
valid = TextUtil.fastReplace(valid,
|
||||
"X", Integer.toString(AbilityUtils.calculateAmount(host, "X", sa)));
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(valid, "creature")) {
|
||||
Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard.FN_GET_RULES);
|
||||
cards = Lists.newArrayList(Iterables.filter(cards, cpp));
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(valid, "equipment")) {
|
||||
Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.Presets.IS_EQUIPMENT, PaperCard.FN_GET_RULES);
|
||||
cards = Lists.newArrayList(Iterables.filter(cards, cpp));
|
||||
}
|
||||
if (sa.hasParam("RandomCopied")) {
|
||||
List<PaperCard> copysource = Lists.newArrayList(cards);
|
||||
List<Card> choice = Lists.newArrayList();
|
||||
final String num = sa.getParamOrDefault("RandomNum", "1");
|
||||
int ncopied = AbilityUtils.calculateAmount(host, num, sa);
|
||||
while (ncopied > 0 && !copysource.isEmpty()) {
|
||||
final PaperCard cp = Aggregates.random(copysource);
|
||||
Card possibleCard = Card.fromPaperCard(cp, activator); // Need to temporarily set the Owner so the Game is set
|
||||
|
||||
if (possibleCard.isValid(valid, host.getController(), host, sa)) {
|
||||
if (host.getController().isAI() && possibleCard.getRules() != null && possibleCard.getRules().getAiHints().getRemAIDecks())
|
||||
continue;
|
||||
choice.add(possibleCard);
|
||||
ncopied -= 1;
|
||||
}
|
||||
copysource.remove(cp);
|
||||
}
|
||||
tgtCards = choice;
|
||||
|
||||
System.err.println("Copying random permanent(s): " + tgtCards.toString());
|
||||
} else if (sa.hasParam("DefinedName")) {
|
||||
String name = sa.getParam("DefinedName");
|
||||
if (name.equals("NamedCard")) {
|
||||
if (!host.getNamedCard().isEmpty()) {
|
||||
name = host.getNamedCard();
|
||||
}
|
||||
}
|
||||
|
||||
Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.name(StringOp.EQUALS, name), PaperCard.FN_GET_RULES);
|
||||
cards = Lists.newArrayList(Iterables.filter(cards, cpp));
|
||||
|
||||
if (!cards.isEmpty()) {
|
||||
tgtCards.add(Card.fromPaperCard(cards.get(0), controller));
|
||||
}
|
||||
}
|
||||
} else if (sa.hasParam("Choices")) {
|
||||
Player chooser = activator;
|
||||
if (sa.hasParam("Chooser")) {
|
||||
final String choose = sa.getParam("Chooser");
|
||||
chooser = AbilityUtils.getDefinedPlayers(sa.getHostCard(), choose, sa).get(0);
|
||||
}
|
||||
|
||||
// For Mimic Vat with mutated creature, need to choose one imprinted card
|
||||
CardCollectionView choices = sa.hasParam("Defined") ? getDefinedCardsOrTargeted(sa) : game.getCardsIn(ZoneType.Battlefield);
|
||||
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, host, sa);
|
||||
if (!choices.isEmpty()) {
|
||||
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard");
|
||||
|
||||
if (sa.hasParam("WithDifferentNames")) {
|
||||
// any Number of choices with different names
|
||||
while (!choices.isEmpty()) {
|
||||
Card choosen = chooser.getController().chooseSingleEntityForEffect(choices, sa, title, true, null);
|
||||
|
||||
if (choosen != null) {
|
||||
tgtCards.add(choosen);
|
||||
choices = CardLists.filter(choices, Predicates.not(CardPredicates.sharesNameWith(choosen)));
|
||||
} else if (chooser.getController().confirmAction(sa, PlayerActionConfirmMode.OptionalChoose, Localizer.getInstance().getMessage("lblCancelChooseConfirm"))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Card choosen = chooser.getController().chooseSingleEntityForEffect(choices, sa, title, false, null);
|
||||
if (choosen != null) {
|
||||
tgtCards.add(choosen);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tgtCards = getDefinedCardsOrTargeted(sa);
|
||||
}
|
||||
|
||||
boolean useZoneTable = true;
|
||||
CardZoneTable triggerList = sa.getChangeZoneTable();
|
||||
if (triggerList == null) {
|
||||
@@ -225,21 +118,127 @@ public class CopyPermanentEffect extends TokenEffectBase {
|
||||
MutableBoolean combatChanged = new MutableBoolean(false);
|
||||
TokenCreateTable tokenTable = new TokenCreateTable();
|
||||
|
||||
for (final Card c : tgtCards) {
|
||||
// if it only targets player, it already got all needed cards from defined
|
||||
if (sa.usesTargeting() && !sa.getTargetRestrictions().canTgtPlayer() && !c.canBeTargetedBy(sa)) {
|
||||
continue;
|
||||
}
|
||||
if (sa.hasParam("ForEach")) {
|
||||
for (Player p : AbilityUtils.getDefinedPlayers(host, sa.getParam("ForEach"), sa)) {
|
||||
Card proto = getProtoType(sa, c, controller);
|
||||
proto.addRemembered(p);
|
||||
tokenTable.put(controller, proto, numCopies);
|
||||
if (sa.hasParam("Optional") && !activator.getController().confirmAction(sa, null,
|
||||
Localizer.getInstance().getMessage("lblCopyPermanentConfirm"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int numCopies = sa.hasParam("NumCopies") ? AbilityUtils.calculateAmount(host,
|
||||
sa.getParam("NumCopies"), sa) : 1;
|
||||
|
||||
List<Player> controllers = Lists.newArrayList();
|
||||
if (sa.hasParam("Controller")) {
|
||||
controllers = AbilityUtils.getDefinedPlayers(host, sa.getParam("Controller"), sa);
|
||||
}
|
||||
if (controllers.isEmpty()) {
|
||||
controllers.add(activator);
|
||||
}
|
||||
|
||||
for (final Player controller : controllers) {
|
||||
List<Card> tgtCards = Lists.newArrayList();
|
||||
|
||||
if (sa.hasParam("ValidSupportedCopy")) {
|
||||
List<PaperCard> cards = Lists.newArrayList(StaticData.instance().getCommonCards().getUniqueCards());
|
||||
String valid = sa.getParam("ValidSupportedCopy");
|
||||
if (valid.contains("X")) {
|
||||
valid = TextUtil.fastReplace(valid,
|
||||
"X", Integer.toString(AbilityUtils.calculateAmount(host, "X", sa)));
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(valid, "creature")) {
|
||||
Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard.FN_GET_RULES);
|
||||
cards = Lists.newArrayList(Iterables.filter(cards, cpp));
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(valid, "equipment")) {
|
||||
Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.Presets.IS_EQUIPMENT, PaperCard.FN_GET_RULES);
|
||||
cards = Lists.newArrayList(Iterables.filter(cards, cpp));
|
||||
}
|
||||
if (sa.hasParam("RandomCopied")) {
|
||||
List<PaperCard> copysource = Lists.newArrayList(cards);
|
||||
List<Card> choice = Lists.newArrayList();
|
||||
final String num = sa.getParamOrDefault("RandomNum", "1");
|
||||
int ncopied = AbilityUtils.calculateAmount(host, num, sa);
|
||||
while (ncopied > 0 && !copysource.isEmpty()) {
|
||||
final PaperCard cp = Aggregates.random(copysource);
|
||||
Card possibleCard = Card.fromPaperCard(cp, activator); // Need to temporarily set the Owner so the Game is set
|
||||
|
||||
if (possibleCard.isValid(valid, host.getController(), host, sa)) {
|
||||
if (host.getController().isAI() && possibleCard.getRules() != null && possibleCard.getRules().getAiHints().getRemAIDecks())
|
||||
continue;
|
||||
choice.add(possibleCard);
|
||||
ncopied -= 1;
|
||||
}
|
||||
copysource.remove(cp);
|
||||
}
|
||||
tgtCards = choice;
|
||||
|
||||
System.err.println("Copying random permanent(s): " + tgtCards.toString());
|
||||
} else if (sa.hasParam("DefinedName")) {
|
||||
String name = sa.getParam("DefinedName");
|
||||
if (name.equals("NamedCard")) {
|
||||
if (!host.getNamedCard().isEmpty()) {
|
||||
name = host.getNamedCard();
|
||||
}
|
||||
}
|
||||
|
||||
Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.name(StringOp.EQUALS, name), PaperCard.FN_GET_RULES);
|
||||
cards = Lists.newArrayList(Iterables.filter(cards, cpp));
|
||||
|
||||
if (!cards.isEmpty()) {
|
||||
tgtCards.add(Card.fromPaperCard(cards.get(0), controller));
|
||||
}
|
||||
}
|
||||
} else if (sa.hasParam("Choices")) {
|
||||
Player chooser = activator;
|
||||
if (sa.hasParam("Chooser")) {
|
||||
final String choose = sa.getParam("Chooser");
|
||||
chooser = AbilityUtils.getDefinedPlayers(sa.getHostCard(), choose, sa).get(0);
|
||||
}
|
||||
|
||||
// For Mimic Vat with mutated creature, need to choose one imprinted card
|
||||
CardCollectionView choices = sa.hasParam("Defined") ? getDefinedCardsOrTargeted(sa) : game.getCardsIn(ZoneType.Battlefield);
|
||||
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, host, sa);
|
||||
if (!choices.isEmpty()) {
|
||||
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard");
|
||||
|
||||
if (sa.hasParam("WithDifferentNames")) {
|
||||
// any Number of choices with different names
|
||||
while (!choices.isEmpty()) {
|
||||
Card choosen = chooser.getController().chooseSingleEntityForEffect(choices, sa, title, true, null);
|
||||
|
||||
if (choosen != null) {
|
||||
tgtCards.add(choosen);
|
||||
choices = CardLists.filter(choices, Predicates.not(CardPredicates.sharesNameWith(choosen)));
|
||||
} else if (chooser.getController().confirmAction(sa, PlayerActionConfirmMode.OptionalChoose, Localizer.getInstance().getMessage("lblCancelChooseConfirm"))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Card choosen = chooser.getController().chooseSingleEntityForEffect(choices, sa, title, false, null);
|
||||
if (choosen != null) {
|
||||
tgtCards.add(choosen);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tokenTable.put(controller, getProtoType(sa, c, controller), numCopies);
|
||||
tgtCards = getDefinedCardsOrTargeted(sa);
|
||||
}
|
||||
} // end foreach Card
|
||||
|
||||
for (final Card c : tgtCards) {
|
||||
// if it only targets player, it already got all needed cards from defined
|
||||
if (sa.usesTargeting() && !sa.getTargetRestrictions().canTgtPlayer() && !c.canBeTargetedBy(sa)) {
|
||||
continue;
|
||||
}
|
||||
if (sa.hasParam("ForEach")) {
|
||||
for (Player p : AbilityUtils.getDefinedPlayers(host, sa.getParam("ForEach"), sa)) {
|
||||
Card proto = getProtoType(sa, c, controller);
|
||||
proto.addRemembered(p);
|
||||
tokenTable.put(controller, proto, numCopies);
|
||||
}
|
||||
} else {
|
||||
tokenTable.put(controller, getProtoType(sa, c, controller), numCopies);
|
||||
}
|
||||
} // end foreach Card
|
||||
}
|
||||
|
||||
makeTokenTable(tokenTable, true, triggerList, combatChanged, sa);
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@ public class GoadEffect extends SpellAbilityEffect {
|
||||
final boolean remember = sa.hasParam("RememberGoaded");
|
||||
|
||||
for (final Card tgtC : getDefinedCardsOrTargeted(sa)) {
|
||||
// only pump things in PumpZone
|
||||
// only goad things on the battlefield
|
||||
if (!game.getCardsIn(ZoneType.Battlefield).contains(tgtC)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if pump is a target, make sure we can still target now
|
||||
// make sure we can still target now if using targeting
|
||||
if (sa.usesTargeting() && !sa.getTargetRestrictions().canTgtPlayer() && !tgtC.canBeTargetedBy(sa)) {
|
||||
continue;
|
||||
}
|
||||
@@ -31,16 +31,19 @@ public class GoadEffect extends SpellAbilityEffect {
|
||||
// 701.38d is handled by getGoaded
|
||||
tgtC.addGoad(timestamp, player);
|
||||
|
||||
final GameCommand untilEOT = new GameCommand() {
|
||||
private static final long serialVersionUID = -1731759226844770852L;
|
||||
// currently, only Life of the Party uses Duration$ – Duration$ Permanent
|
||||
if (!sa.hasParam("Duration")) {
|
||||
final GameCommand untilEOT = new GameCommand() {
|
||||
private static final long serialVersionUID = -1731759226844770852L;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
tgtC.removeGoad(timestamp);
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void run() {
|
||||
tgtC.removeGoad(timestamp);
|
||||
}
|
||||
};
|
||||
|
||||
game.getCleanup().addUntil(player, untilEOT);
|
||||
game.getCleanup().addUntil(player, untilEOT);
|
||||
}
|
||||
|
||||
if (remember && tgtC.isGoaded()) {
|
||||
sa.getHostCard().addRemembered(tgtC);
|
||||
|
||||
@@ -535,7 +535,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
return currentStateName;
|
||||
}
|
||||
|
||||
// use by CopyPermament
|
||||
// use by CopyPermanent
|
||||
public void setStates(Map<CardStateName, CardState> map) {
|
||||
states.clear();
|
||||
states.putAll(map);
|
||||
|
||||
17
forge-gui/res/cardsfolder/upcoming/life_of_the_party.txt
Normal file
17
forge-gui/res/cardsfolder/upcoming/life_of_the_party.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
Name:Life of the Party
|
||||
ManaCost:3 R
|
||||
Types:Creature Elemental
|
||||
PT:0/1
|
||||
K:First Strike
|
||||
K:Trample
|
||||
K:Haste
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME attacks, it gets +X/+0 until end of turn, where X is the number of creatures you control.
|
||||
SVar:TrigPump:DB$ Pump | NumAtt$ X
|
||||
SVar:X:Count$Valid Creature.YouCtrl
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self+nonToken | Execute$ TrigCopyPermanent | TriggerDescription$ When CARDNAME enters the battlefield, if it's not a token, each opponent creates a token that's a copy of it. The tokens are goaded for the rest of the game. (They attack each combat if able and attack a player other than you if able.)
|
||||
SVar:TrigCopyPermanent:DB$ CopyPermanent | Defined$ TriggeredCard | Controller$ Opponent | RememberTokens$ True | SubAbility$ DBGoad
|
||||
SVar:DBGoad:DB$ Goad | Defined$ Remembered | Duration$ Permanent | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:NeedsToPlayVar:X GE3
|
||||
SVar:HasAttackEffect:TRUE
|
||||
Oracle:First strike, trample, haste\nWhenever Life of the Party attacks, it gets +X/+0 until end of turn, where X is the number of creatures you control.\nWhen Life of the Party enters the battlefield, if it's not a token, each opponent creates a token that's a copy of it. The tokens are goaded for the rest of the game. (They attack each combat if able and attack a player other than you if able.)
|
||||
Reference in New Issue
Block a user