Merge branch 'roll_die_as_cost' into 'master'

Add Clay Golem and implement roll dice as cost

See merge request core-developers/forge!5014
This commit is contained in:
Michael Kamensky
2021-07-14 10:21:13 +00:00
14 changed files with 136 additions and 2 deletions

View File

@@ -267,6 +267,15 @@ public class AiCostDecision extends CostDecisionMakerBase {
return PaymentDecision.number(c); return PaymentDecision.number(c);
} }
@Override
public PaymentDecision visit(CostRollDice cost) {
Integer c = cost.convertAmount();
if (c == null) {
c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability);
}
return PaymentDecision.number(c);
}
@Override @Override
public PaymentDecision visit(CostGainControl cost) { public PaymentDecision visit(CostGainControl cost) {
if (cost.payCostFromSource()) { if (cost.payCostFromSource()) {

View File

@@ -363,6 +363,13 @@ public class Cost implements Serializable {
return new CostFlipCoin(splitStr[0]); return new CostFlipCoin(splitStr[0]);
} }
if (parse.startsWith("RollDice<")) {
// RollDice<NumDice/Sides/ResultSVar>
final String[] splitStr = abCostParse(parse, 4);
final String description = splitStr.length > 3 ? splitStr[3] : null;
return new CostRollDice(splitStr[0], splitStr[1], splitStr[2], description);
}
if (parse.startsWith("Discard<")) { if (parse.startsWith("Discard<")) {
// Discard<NumCards/Type> // Discard<NumCards/Type>
final String[] splitStr = abCostParse(parse, 3); final String[] splitStr = abCostParse(parse, 3);

View File

@@ -0,0 +1,68 @@
package forge.game.cost;
import forge.game.ability.effects.RollDiceEffect;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
/**
* This is for the "RollDice" Cost
*/
public class CostRollDice extends CostPart {
/**
* Serializables need a version ID.
*/
private static final long serialVersionUID = 1L;
private final String resultSVar;
/**
* Instantiates a new cost RollDice.
*
* @param amount
* the amount
*/
public CostRollDice(final String amount, final String sides, final String resultSVar, final String description) {
super(amount, sides, description);
this.resultSVar = resultSVar;
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#canPay(forge.card.spellability.SpellAbility,
* forge.Card, forge.Player, forge.card.cost.Cost)
*/
@Override
public final boolean canPay(final SpellAbility ability, final Player payer) {
return true;
}
@Override
public final String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("Roll ").append(getAmount());
if (this.getTypeDescription() == null) {
sb.append("d").append(getType());
} else {
sb.append(" ").append(this.getTypeDescription());
}
return sb.toString();
}
@Override
public boolean payAsDecided(Player payer, PaymentDecision pd, SpellAbility sa) {
int sides = Integer.parseInt(getType());
int result = RollDiceEffect.rollDiceForPlayer(sa, payer, pd.c, sides);
sa.setSVar(resultSVar, Integer.toString(result));
return true;
}
public <T> T accept(ICostVisitor<T> visitor) {
return visitor.visit(this);
}
}

View File

@@ -12,6 +12,7 @@ public interface ICostVisitor<T> {
T visit(CostExiledMoveToGrave cost); T visit(CostExiledMoveToGrave cost);
T visit(CostExert cost); T visit(CostExert cost);
T visit(CostFlipCoin cost); T visit(CostFlipCoin cost);
T visit(CostRollDice cost);
T visit(CostMill cost); T visit(CostMill cost);
T visit(CostAddMana cost); T visit(CostAddMana cost);
T visit(CostPayLife cost); T visit(CostPayLife cost);
@@ -84,6 +85,11 @@ public interface ICostVisitor<T> {
return null; return null;
} }
@Override
public T visit(CostRollDice cost) {
return null;
}
@Override @Override
public T visit(CostMill cost) { public T visit(CostMill cost) {
return null; return null;

View File

@@ -53,6 +53,7 @@ public class MessageUtil {
case Protection: case Protection:
return Localizer.getInstance().getMessage("lblPlayerChooseValue", choser, value); return Localizer.getInstance().getMessage("lblPlayerChooseValue", choser, value);
case RollDice: case RollDice:
case PutCounter:// For Clay Golem cost text
return value; return value;
case Vote: case Vote:
String chooser = StringUtils.capitalize(mayBeYou(player, target)); String chooser = StringUtils.capitalize(mayBeYou(player, target));

View File

@@ -0,0 +1,9 @@
Name:Clay Golem
ManaCost:4
Types:Artifact Creature Golem
PT:4/4
A:AB$ PutCounter | Cost$ 6 RollDice<1/8/X> | ConditionPresent$ Card.Self+IsNotMonstrous | Monstrosity$ True | CounterNum$ X | CounterType$ P1P1 | StackDescription$ SpellDescription | SpellDescription$ Monstrosity X, where X is the result. (If this creature isn't monstrous, put X +1/+1 counters on it and it becomes monstrous.)
T:Mode$ BecomeMonstrous | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigDestroy | TriggerDescription$ Berserk — When CARDNAME becomes monstrous, destroy target permanent.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Permanent
DeckHas:Ability$Counters
Oracle:{6}, Roll a d8: Monstrosity X, where X is the result. (If this creature isn't monstrous, put X +1/+1 counters on it and it becomes monstrous.)\nBerserk — When Clay Golem becomes monstrous, destroy target permanent.

View File

@@ -1725,6 +1725,7 @@ lblDoYouWantPayNLife=Möchtest du {0} Leben bezahlen?
lblDoyouWantTo=Möchtest du lblDoyouWantTo=Möchtest du
lblDoYouWantMillNCardsOrDoAction=Möchtest du {0} Karte(n) von der Bibliothek auf den Friedhof legen? {1} lblDoYouWantMillNCardsOrDoAction=Möchtest du {0} Karte(n) von der Bibliothek auf den Friedhof legen? {1}
lblDoYouWantFlipNCoinAction=Möchtest du {0} Münze(n) werfen? lblDoYouWantFlipNCoinAction=Möchtest du {0} Münze(n) werfen?
lblDoYouWantRollNDiceAction=Do you want to roll {0}{1}?
lblDoYouWantRemoveNTargetTypeCounterFromCard=Möchtest du {0} {1}-Marken von {2} entfernen? lblDoYouWantRemoveNTargetTypeCounterFromCard=Möchtest du {0} {1}-Marken von {2} entfernen?
lblDoYouWantRemoveCountersFromCard=Möchtest du Marken von {0} entfernen? lblDoYouWantRemoveCountersFromCard=Möchtest du Marken von {0} entfernen?
lblDoYouWantExileNCardsFromYourLibrary=Möchtest du {0} Karte(n) von deiner Bibliothek ins Exil schicken? lblDoYouWantExileNCardsFromYourLibrary=Möchtest du {0} Karte(n) von deiner Bibliothek ins Exil schicken?

View File

@@ -1725,6 +1725,7 @@ lblDoYouWantPayNLife=Do you want to pay {0} life?
lblDoyouWantTo=Do you want to lblDoyouWantTo=Do you want to
lblDoYouWantMillNCardsOrDoAction=Do you want to mill {0} card(s)? {1} lblDoYouWantMillNCardsOrDoAction=Do you want to mill {0} card(s)? {1}
lblDoYouWantFlipNCoinAction=Do you want to flip {0} coin(s)? lblDoYouWantFlipNCoinAction=Do you want to flip {0} coin(s)?
lblDoYouWantRollNDiceAction=Do you want to roll {0}{1}?
lblDoYouWantRemoveNTargetTypeCounterFromCard=Do you want to remove {0} {1} counter from {2}? lblDoYouWantRemoveNTargetTypeCounterFromCard=Do you want to remove {0} {1} counter from {2}?
lblDoYouWantRemoveCountersFromCard=Do you want to remove counters from {0}? lblDoYouWantRemoveCountersFromCard=Do you want to remove counters from {0}?
lblDoYouWantExileNCardsFromYourLibrary=Do you want to exile {0} card(s) from your library? lblDoYouWantExileNCardsFromYourLibrary=Do you want to exile {0} card(s) from your library?

View File

@@ -1724,6 +1724,7 @@ lblDoYouWantPayNLife=¿Quieres pagar {0} de vida?
lblDoyouWantTo=¿Quieres lblDoyouWantTo=¿Quieres
lblDoYouWantMillNCardsOrDoAction=¿Quieres moler {0} carta(s)? {1} lblDoYouWantMillNCardsOrDoAction=¿Quieres moler {0} carta(s)? {1}
lblDoYouWantFlipNCoinAction=¿Quieres lanzar {0} moneda(s)? lblDoYouWantFlipNCoinAction=¿Quieres lanzar {0} moneda(s)?
lblDoYouWantRollNDiceAction=Do you want to roll {0}{1}?
lblDoYouWantRemoveNTargetTypeCounterFromCard=¿Quieres quitar el contador {0} {1} de {2}? lblDoYouWantRemoveNTargetTypeCounterFromCard=¿Quieres quitar el contador {0} {1} de {2}?
lblDoYouWantRemoveCountersFromCard=¿Quieres quitar los contadores de {0}? lblDoYouWantRemoveCountersFromCard=¿Quieres quitar los contadores de {0}?
lblDoYouWantExileNCardsFromYourLibrary=¿Quieres exiliar {0} carta(s) de tu biblioteca? lblDoYouWantExileNCardsFromYourLibrary=¿Quieres exiliar {0} carta(s) de tu biblioteca?

View File

@@ -1724,6 +1724,7 @@ lblDoYouWantPayNLife=Vuoi pagare {0} punti vita?
lblDoyouWantTo=Vuoi lblDoyouWantTo=Vuoi
lblDoYouWantMillNCardsOrDoAction=Vuoi macinare {0} carta/e? {1} lblDoYouWantMillNCardsOrDoAction=Vuoi macinare {0} carta/e? {1}
lblDoYouWantFlipNCoinAction=Vuoi lanciare {0} moneta/e? lblDoYouWantFlipNCoinAction=Vuoi lanciare {0} moneta/e?
lblDoYouWantRollNDiceAction=Do you want to roll {0}{1}?
lblDoYouWantRemoveNTargetTypeCounterFromCard=Vuoi rimuovere {0} segnalino {1} da {2}? lblDoYouWantRemoveNTargetTypeCounterFromCard=Vuoi rimuovere {0} segnalino {1} da {2}?
lblDoYouWantRemoveCountersFromCard=Vuoi rimuovere i segnalini da {0}? lblDoYouWantRemoveCountersFromCard=Vuoi rimuovere i segnalini da {0}?
lblDoYouWantExileNCardsFromYourLibrary=Vuoi esiliare {0} carta/e dal tuo grimorio? lblDoYouWantExileNCardsFromYourLibrary=Vuoi esiliare {0} carta/e dal tuo grimorio?

View File

@@ -1724,7 +1724,8 @@ lblDoYouWantPay=プレイしますか?
lblDoYouWantPayNLife={0}点のライフを支払いますか? lblDoYouWantPayNLife={0}点のライフを支払いますか?
lblDoyouWantTo=この行動をしてもいい? lblDoyouWantTo=この行動をしてもいい?
lblDoYouWantMillNCardsOrDoAction={0}枚のカードを切削しますか? {1} lblDoYouWantMillNCardsOrDoAction={0}枚のカードを切削しますか? {1}
lblDoYouWantFlipNCoinOrDoAction={0}枚のコイントスをしますか? {1} lblDoYouWantFlipNCoinAction={0}枚のコイントスをしますか?
lblDoYouWantRollNDiceAction={0}{1}を投げますか?
lblDoYouWantRemoveNTargetTypeCounterFromCard={2}から {1}個の {0}カウンターを取り除きますか? lblDoYouWantRemoveNTargetTypeCounterFromCard={2}から {1}個の {0}カウンターを取り除きますか?
lblDoYouWantRemoveCountersFromCard={0}からカウンターを取り除きますか? lblDoYouWantRemoveCountersFromCard={0}からカウンターを取り除きますか?
lblDoYouWantExileNCardsFromYourLibrary=ライブラリーから {0}枚のカードを追放しますか? lblDoYouWantExileNCardsFromYourLibrary=ライブラリーから {0}枚のカードを追放しますか?

View File

@@ -1725,6 +1725,7 @@ lblDoYouWantPayNLife=你想要支付{0}点生命吗?
lblDoyouWantTo=你想要 lblDoyouWantTo=你想要
lblDoYouWantMillNCardsOrDoAction=你想要磨{0}张牌吗? {1} lblDoYouWantMillNCardsOrDoAction=你想要磨{0}张牌吗? {1}
lblDoYouWantFlipNCoinAction=你想要抛{0}个硬币吗? lblDoYouWantFlipNCoinAction=你想要抛{0}个硬币吗?
lblDoYouWantRollNDiceAction=Do you want to roll {0}{1}?
lblDoYouWantRemoveNTargetTypeCounterFromCard=你想要从{2}移除{0}个{1}指示物吗? lblDoYouWantRemoveNTargetTypeCounterFromCard=你想要从{2}移除{0}个{1}指示物吗?
lblDoYouWantRemoveCountersFromCard=你想要从{0}删除指示物吗? lblDoYouWantRemoveCountersFromCard=你想要从{0}删除指示物吗?
lblDoYouWantExileNCardsFromYourLibrary=你想要从你的牌库放逐{0}张牌吗? lblDoYouWantExileNCardsFromYourLibrary=你想要从你的牌库放逐{0}张牌吗?

View File

@@ -482,6 +482,22 @@ public class HumanCostDecision extends CostDecisionMakerBase {
return PaymentDecision.number(c); return PaymentDecision.number(c);
} }
@Override
public PaymentDecision visit(final CostRollDice cost) {
final String amount = cost.getAmount();
Integer c = cost.convertAmount();
if (c == null) {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
if (!player.getController().confirmPayment(cost, Localizer.getInstance().getMessage("lblDoYouWantRollNDiceAction", String.valueOf(c), "d" + cost.getType()), ability)) {
return null;
}
return PaymentDecision.number(c);
}
@Override @Override
public PaymentDecision visit(final CostGainControl cost) { public PaymentDecision visit(final CostGainControl cost) {
final String amount = cost.getAmount(); final String amount = cost.getAmount();

View File

@@ -349,6 +349,18 @@ public class HumanPlay {
else else
part.payAsDecided(p, pd, sourceAbility); part.payAsDecided(p, pd, sourceAbility);
} }
else if (part instanceof CostRollDice) {
if (!part.canPay(sourceAbility, p)) {
return false;
}
PaymentDecision pd = part.accept(hcd);
if (pd == null)
return false;
else
part.payAsDecided(p, pd, sourceAbility);
}
else if (part instanceof CostDamage) { else if (part instanceof CostDamage) {
if (!part.canPay(sourceAbility, p)) { if (!part.canPay(sourceAbility, p)) {
return false; return false;