MH3: nethergoyf.txt + support (#5311)

This commit is contained in:
Northmoc
2024-05-29 06:58:50 -04:00
committed by GitHub
parent 9fa35cb90e
commit 895b7b54c5
14 changed files with 73 additions and 12 deletions

View File

@@ -202,12 +202,23 @@ public class CostExile extends CostPartWithList {
type = TextUtil.fastReplace(type, "+withSharedCardType", "");
}
int nTypes = -1;
if (type.contains("+withTypesGE")) {
String num = type.split("withTypesGE")[1];
type = TextUtil.fastReplace(type, TextUtil.concatNoSpace("+withTypesGE", num), "");
nTypes = Integer.parseInt(num);
}
if (!type.contains("X") || ability.getXManaCostPaid() != null) {
list = CardLists.getValidCards(list, type.split(";"), payer, source, ability);
}
int amount = this.getAbilityAmount(ability);
if (nTypes > -1) {
if (CardFactoryUtil.getCardTypesFromList(list) < nTypes) return false;
}
if (sharedType) { // will need more logic if cost ever wants more than 2 that share a type
if (list.size() < amount) return false;
for (int i = 0; i < list.size(); i++) {

View File

@@ -0,0 +1,10 @@
Name:Nethergoyf
ManaCost:B
Types:Creature Lhurgoyf
PT:*/1+*
S:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$ Count$ValidGraveyard Card.YouOwn$CardTypes | SetToughness$ Count$ValidGraveyard Card.YouOwn$CardTypes/Plus.1 | Description$ CARDNAME's power is equal to the number of card types among cards in your graveyard and its toughness is equal to that number plus 1.
K:Escape:2 B ExileFromGrave<X/Card.Other+withTypesGE4/other cards from your graveyard with four or more card types among them>
SVar:X:Count$xPaid
AI:RemoveDeck:All
DeckHints:Ability$Discard|Sacrifice|Graveyard
Oracle:Nethergoyf's power is equal to the number of card types among cards in your graveyard and its toughness is equal to that number plus 1.\nEscape—{2}{B}, Exile any number of other cards from your graveyard with four or more card types among them. (You may cast this card from your graveyard for its escape cost.)

View File

@@ -2479,6 +2479,7 @@ lblSelectATargetToSacrifice=Wähle ein(e) {0} zum Opfern (noch {1})
lblSelectOneOfCardsToTapAlreadyChosen=Wähle eine Karte zum tappen. Bereits gewählt:
lblSelectACreatureToTap=Wähle eine Kreatur zum Tappen.
lblSelectToExile=Select {0} or more to exile
lblSelectAnyNumToExile=Select any number to exile
lblEnoughValidCardNotToPayTheCost=Nicht genug gültige Karten zum Tappen übrig um die Kosten zu bezahlen.
lblCostPaymentInvalid=Bezahlung der Kosten unmöglich
lblSelectATargetToTap=Wähle ein(e) {0} zum Tappen (noch {1})

View File

@@ -2492,6 +2492,7 @@ lblSelectATargetToSacrifice=Select {0} to sacrifice ({1} left)
lblSelectOneOfCardsToTapAlreadyChosen=Select one of the cards to tap. Already chosen:
lblSelectACreatureToTap=Select a creature to tap.
lblSelectToExile=Select {0} or more to exile
lblSelectAnyNumToExile=Select any number to exile
lblCollectEvidence=Exile evidence with a total CMC {0} or more
lblEnoughValidCardNotToPayTheCost=Not enough valid cards left to tap to pay the cost.
lblCostPaymentInvalid=Cost payment invalid

View File

@@ -2480,6 +2480,7 @@ lblSelectATargetToSacrifice=Selecciona un {0} para sacrificar ({1} pendiente)
lblSelectOneOfCardsToTapAlreadyChosen=Selecciona una de las cartas para girar. Ya elegido:
lblSelectACreatureToTap=Selecciona una criatura para girar.
lblSelectToExile=Selecciona {0} o más para exilar
lblSelectAnyNumToExile=Select any number to exile
lblEnoughValidCardNotToPayTheCost=No quedan suficientes cartas válidas para girar para pagar el coste.
lblCostPaymentInvalid=Pago del coste no válido
lblSelectATargetToTap=Selecciona un/a {0} para girar ({1} pendiente)

View File

@@ -2483,6 +2483,7 @@ lblSelectATargetToSacrifice=Sélectionnez {0} à sacrifier ({1} à gauche)
lblSelectOneOfCardsToTapAlreadyChosen=S\u00e9lectionnez une des cartes \u00e0 tapoter. Déjà choisi :
lblSelectACreatureToTap=S\u00e9lectionnez une cr\u00e9ature \u00e0 engager.
lblSelectToExile=Sélectionnez {0} ou plus pour exiler
lblSelectAnyNumToExile=Select any number to exile
lblEnoughValidCardNotToPayTheCost=Il ne reste plus assez de cartes valides à toucher pour payer le coût.
lblCostPaymentInvalid=Paiement de coût invalide
lblSelectATargetToTap=Sélectionnez un(e) {0} à appuyer ({1} à gauche)

View File

@@ -2480,6 +2480,7 @@ lblSelectATargetToSacrifice=Seleziona una carta {0} da scarificare ({1} rimasta/
lblSelectOneOfCardsToTapAlreadyChosen=Seleziona una delle carta da tappare. Già scelto:
lblSelectACreatureToTap=Seleziona una creatura da tappare.
lblSelectToExile=Seleziona {0} o più per esiliare
lblSelectAnyNumToExile=Select any number to exile
lblEnoughValidCardNotToPayTheCost=Non sono rimaste abbastanza carte valide da tappare per pagare il costo
lblCostPaymentInvalid=Pagamento del costo non valido
lblSelectATargetToTap=Seleziona una carta {0} da tapapre ({1} rimasta/e)

View File

@@ -2479,6 +2479,7 @@ lblSelectATargetToSacrifice=生け贄に捧げ {0}を選択(残り{1}
lblSelectOneOfCardsToTapAlreadyChosen=タップするカードを選ぶ。既に選択:
lblSelectACreatureToTap=タップするクリーチャーを選ぶ。
lblSelectToExile=追放するには{0}個以上を選択してください
lblSelectAnyNumToExile=Select any number to exile
lblEnoughValidCardNotToPayTheCost=コストを支払いためにタップできるカードが足りません。
lblCostPaymentInvalid=無効な支払い
lblSelectATargetToTap=タップする {0}を選択(残り{1}

View File

@@ -2555,6 +2555,7 @@ lblSelectATargetToSacrifice=Selecione {0} para sacrificar ({1} restantes)
lblSelectOneOfCardsToTapAlreadyChosen=Escolha uma das cartas para virar. Já escolhido\:
lblSelectACreatureToTap=Escolha as criaturas para virar.
lblSelectToExile=Selecione {0} ou mais para exilar
lblSelectAnyNumToExile=Select any number to exile
lblEnoughValidCardNotToPayTheCost=Cartas válidas insuficientes para pagar o custo.
lblCostPaymentInvalid=Custo de pagamento inválido
lblSelectATargetToTap=Escolha um(n) {0} para virar ({1} restante)

View File

@@ -2484,6 +2484,7 @@ lblSelectATargetToSacrifice=选择一个{0}进行牺牲(还剩{1}
lblSelectOneOfCardsToTapAlreadyChosen=选择其中的一张进行横置。已经选择:
lblSelectACreatureToTap=选择一个生物进行横置
lblSelectToExile=选择{0}个或更多要放逐的
lblSelectAnyNumToExile=Select any number to exile
lblEnoughValidCardNotToPayTheCost=没有足够的有效卡牌用于支付费用。
lblCostPaymentInvalid=付费失败
lblSelectATargetToTap=选择{0}进行横置(还剩{1}

View File

@@ -24,8 +24,8 @@ public class InputSelectCardsFromList extends InputSelectEntitiesFromList<Card>
super(controller, min, max, validCards, sa);
}
public InputSelectCardsFromList(final PlayerControllerHuman controller, final int min, final int max, final FCollectionView<Card> validCards, final SpellAbility sa, final int tally) {
super(controller, min, max, validCards, sa, tally);
public InputSelectCardsFromList(final PlayerControllerHuman controller, final int min, final int max, final FCollectionView<Card> validCards, final SpellAbility sa, final String tallyType, final int tally) {
super(controller, min, max, validCards, sa, tallyType, tally);
}
}

View File

@@ -5,6 +5,7 @@ import java.util.Collection;
import java.util.List;
import forge.game.GameEntity;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardLists;
import forge.game.card.CardView;
@@ -32,15 +33,15 @@ public class InputSelectEntitiesFromList<T extends GameEntity> extends InputSele
protected Iterable<PlayerZoneUpdate> zonesShown; // want to hide these zones when input done
public InputSelectEntitiesFromList(final PlayerControllerHuman controller, final int min, final int max, final FCollectionView<T> validChoices0) {
this(controller, min, max, validChoices0, null, 0);
this(controller, min, max, validChoices0, null, "", 0);
}
public InputSelectEntitiesFromList(final PlayerControllerHuman controller, final int min, final int max, final FCollectionView<T> validChoices0, final SpellAbility sa0) {
this(controller, min, max, validChoices0, sa0, 0);
this(controller, min, max, validChoices0, sa0, "", 0);
}
public InputSelectEntitiesFromList(final PlayerControllerHuman controller, final int min, final int max, final FCollectionView<T> validChoices0, final SpellAbility sa0, final int tally0) {
super(controller, Math.min(min, validChoices0.size()), Math.min(max, validChoices0.size()), sa0, tally0);
public InputSelectEntitiesFromList(final PlayerControllerHuman controller, final int min, final int max, final FCollectionView<T> validChoices0, final SpellAbility sa0, final String tallyType0, final int tally0) {
super(controller, Math.min(min, validChoices0.size()), Math.min(max, validChoices0.size()), sa0, tallyType0, tally0);
validChoices = validChoices0;
if (min > validChoices.size()) { // pfps does this really do anything useful??
System.out.println(String.format("Trying to choose at least %d things from a list with only %d things!", min, validChoices.size()));
@@ -142,10 +143,17 @@ public class InputSelectEntitiesFromList<T extends GameEntity> extends InputSele
}
else if (sa.getPayCosts().hasSpecificCostType(CostExile.class) && tally > 0) {
msg.append("\n").append(Localizer.getInstance().getMessage("lblCMC")).append(": ");
msg.append(CardLists.getTotalCMC((FCollection<Card>)getSelected())).append(" / ").append(tally);
msg.append("\n");
if (tallyType.equals("CMC")) {
msg.append(Localizer.getInstance().getMessage("lblCMC")).append(": ");
msg.append(CardLists.getTotalCMC((FCollection<Card>)getSelected())).append(" / ").append(tally);
} else if (tallyType.equals("Types")) {
msg.append(Localizer.getInstance().getMessage("lblTypes")).append(": ");
msg.append(AbilityUtils.countCardTypesFromList((FCollection<Card>)getSelected(), false));
msg.append(" / ").append(tally);
}
}
}
}
return msg.toString();
}

View File

@@ -23,6 +23,7 @@ public abstract class InputSelectManyBase<T extends GameEntity> extends InputSyn
protected boolean allowCancel = false;
protected SpellAbility sa = null;
protected CardView card;
protected String tallyType;
protected int tally;
protected String message = "Source-Card-Name - Select %d more card(s)";
@@ -44,12 +45,13 @@ public abstract class InputSelectManyBase<T extends GameEntity> extends InputSyn
}
}
protected InputSelectManyBase(final PlayerControllerHuman controller, final int min, final int max, final SpellAbility sa0, final int tally0) {
protected InputSelectManyBase(final PlayerControllerHuman controller, final int min, final int max, final SpellAbility sa0, final String tallyType0, final int tally0) {
this(controller,min,max);
this.sa = sa0;
if (sa0 != null) {
this.card = sa0.getView().getHostCard();
}
this.tallyType = tallyType0;
this.tally = tally0;
}

View File

@@ -21,6 +21,7 @@ import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets;
@@ -84,7 +85,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
CardCollection list = CardLists.filter(player.getCardsIn(ZoneType.Graveyard), CardPredicates.canExiledBy(ability, isEffect()));
final int total = AbilityUtils.calculateAmount(source, cost.getAmount(), ability);
final InputSelectCardsFromList inp =
new InputSelectCardsFromList(controller, 0, list.size(), list, ability, total);
new InputSelectCardsFromList(controller, 0, list.size(), list, ability, "CMC", total);
inp.setMessage(Localizer.getInstance().getMessage("lblCollectEvidence", total));
inp.setCancelAllowed(true);
inp.showAndWait();
@@ -265,6 +266,12 @@ public class HumanCostDecision extends CostDecisionMakerBase {
sharedType = true;
type = TextUtil.fastReplace(type, "+withSharedCardType", "");
}
int nTypes = -1;
if (type.contains("+withTypesGE")) {
String num = type.split("withTypesGE")[1];
type = TextUtil.fastReplace(type, TextUtil.concatNoSpace("+withTypesGE", num), "");
nTypes = Integer.parseInt(num);
}
CardCollection list;
if (cost.zoneRestriction != 1) {
@@ -286,7 +293,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
int needed = Integer.parseInt(cost.getAmount().split("\\+")[0]);
final int total = AbilityUtils.calculateAmount(source, totalM, ability);
final InputSelectCardsFromList inp =
new InputSelectCardsFromList(controller, needed, list.size(), list, ability, total);
new InputSelectCardsFromList(controller, needed, list.size(), list, ability, "CMC", total);
inp.setMessage(Localizer.getInstance().getMessage("lblSelectToExile", Lang.getNumeral(needed)));
inp.setCancelAllowed(true);
inp.showAndWait();
@@ -297,6 +304,21 @@ public class HumanCostDecision extends CostDecisionMakerBase {
return PaymentDecision.card(inp.getSelected());
}
if (nTypes > -1) {
final InputSelectCardsFromList inp = new InputSelectCardsFromList(controller, 1, list.size(), list,
ability, "Types", nTypes);
inp.setMessage(cost.getAmount().equals("X") ?
Localizer.getInstance().getMessage("lblSelectAnyNumToExile") :
Localizer.getInstance().getMessage("lblSelectToExile", Lang.getNumeral(nTypes)));
inp.setCancelAllowed(true);
inp.showAndWait();
if (inp.hasCancelled() ||
!Expressions.compare(CardFactoryUtil.getCardTypesFromList(list), "GE", nTypes)) {
return null;
}
return PaymentDecision.card(inp.getSelected());
}
int c = cost.getAbilityAmount(ability);
if (list.size() < c) {