mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 04:38:00 +00:00
Merged changes from trunk to GuiRefactoring: 27239-27260
This commit is contained in:
@@ -13,19 +13,19 @@ import forge.game.player.RegisteredPlayer;
|
||||
public enum GameType {
|
||||
|
||||
// deck composition rules, isPoolRestricted, can sideboard between matches
|
||||
Sealed (DeckFormat.Limited, true, true, true, "Sealed", null),
|
||||
Draft (DeckFormat.Limited, true, true, true, "Draft", null),
|
||||
Winston (DeckFormat.Limited, true, true, true, "Winston", null),
|
||||
Gauntlet (DeckFormat.Limited, true, true, true, "Gauntlet", null),
|
||||
Quest (DeckFormat.QuestDeck, true, true, false, "Quest", null),
|
||||
QuestDraft (DeckFormat.Limited, true, true, true, "Quest Draft", null),
|
||||
Constructed (DeckFormat.Constructed, false, true, true, "Constructed", null),
|
||||
Vanguard (DeckFormat.Vanguard, true, true, true, "Vanguard", null),
|
||||
Commander (DeckFormat.Commander, false, false, false, "Commander", null),
|
||||
Planechase (DeckFormat.Planechase, false, false, true, "Planechase", null),
|
||||
Archenemy (DeckFormat.Archenemy, false, false, true, "Archenemy", null),
|
||||
ArchenemyRumble (DeckFormat.Archenemy, false, false, true, "Archenemy Rumble", null),
|
||||
MomirBasic (DeckFormat.Constructed, false, false, false, "Momir Basic", new Function<RegisteredPlayer, Deck>() {
|
||||
Sealed (DeckFormat.Limited, true, true, true, "Sealed", "", null),
|
||||
Draft (DeckFormat.Limited, true, true, true, "Draft", "", null),
|
||||
Winston (DeckFormat.Limited, true, true, true, "Winston", "", null),
|
||||
Gauntlet (DeckFormat.Limited, true, true, true, "Gauntlet", "", null),
|
||||
Quest (DeckFormat.QuestDeck, true, true, false, "Quest", "", null),
|
||||
QuestDraft (DeckFormat.Limited, true, true, true, "Quest Draft", "", null),
|
||||
Constructed (DeckFormat.Constructed, false, true, true, "Constructed", "", null),
|
||||
Vanguard (DeckFormat.Vanguard, true, true, true, "Vanguard", "Each player has a special \"Avatar\" card that affects the game.", null),
|
||||
Commander (DeckFormat.Commander, false, false, false, "Commander", "Each player has a legendary \"General\" card which can be cast at any time and determines deck colors.", null),
|
||||
Planechase (DeckFormat.Planechase, false, false, true, "Planechase", "Plane cards apply global effects. Plane card changed when a player rolls \"Chaos\" on the planar die.", null),
|
||||
Archenemy (DeckFormat.Archenemy, false, false, true, "Archenemy", "One player is the Archenemy and can play scheme cards.", null),
|
||||
ArchenemyRumble (DeckFormat.Archenemy, false, false, true, "Archenemy Rumble", "All players are Archenemies and can play scheme cards.", null),
|
||||
MomirBasic (DeckFormat.Constructed, false, false, false, "Momir Basic", "Each player has a deck containing 60 basic lands and the Momir Vig avatar.", new Function<RegisteredPlayer, Deck>() {
|
||||
@Override
|
||||
public Deck apply(RegisteredPlayer player) {
|
||||
Deck deck = new Deck();
|
||||
@@ -43,15 +43,16 @@ public enum GameType {
|
||||
|
||||
private final DeckFormat deckFormat;
|
||||
private final boolean isCardPoolLimited, canSideboard, addWonCardsMidGame;
|
||||
private final String name;
|
||||
private final String name, description;
|
||||
private final Function<RegisteredPlayer, Deck> deckAutoGenerator;
|
||||
|
||||
GameType(DeckFormat deckFormat0, boolean isCardPoolLimited0, boolean canSideboard0, boolean addWonCardsMidgame0, String name0, Function<RegisteredPlayer, Deck> deckAutoGenerator0) {
|
||||
GameType(DeckFormat deckFormat0, boolean isCardPoolLimited0, boolean canSideboard0, boolean addWonCardsMidgame0, String name0, String description0, Function<RegisteredPlayer, Deck> deckAutoGenerator0) {
|
||||
deckFormat = deckFormat0;
|
||||
isCardPoolLimited = isCardPoolLimited0;
|
||||
canSideboard = canSideboard0;
|
||||
addWonCardsMidGame = addWonCardsMidgame0;
|
||||
name = name0;
|
||||
description = description0;
|
||||
deckAutoGenerator = deckAutoGenerator0;
|
||||
}
|
||||
|
||||
@@ -104,4 +105,8 @@ public enum GameType {
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ import java.util.StringTokenizer;
|
||||
if (abSub != null) {
|
||||
sb.append(abSub.getStackDescription());
|
||||
}
|
||||
|
||||
|
||||
if (sa.hasParam("Announce")) {
|
||||
String svar = sa.getParam("Announce");
|
||||
int amount = CardFactoryUtil.xCount(sa.getHostCard(), sa.getSVar(svar));
|
||||
|
||||
@@ -2535,7 +2535,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
sb.indexOf("Storm (When you cast this spell, copy it for each spell cast before it this turn.") + 81,
|
||||
" You may choose new targets for the copies.");
|
||||
}
|
||||
} else if (keyword.contains("Replicate") && !sb.toString().contains("you paid its replicate cost.")) {
|
||||
} else if (keyword.startsWith("Replicate") && !sb.toString().contains("you paid its replicate cost.")) {
|
||||
if (sb.toString().endsWith("\r\n\r\n")) {
|
||||
sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + 3);
|
||||
}
|
||||
@@ -4181,8 +4181,9 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
public final void addMultiKickerMagnitude(final int n) { this.multiKickerMagnitude += n; }
|
||||
public final void setKickerMagnitude(final int n) { this.multiKickerMagnitude = n; }
|
||||
public final int getKickerMagnitude() {
|
||||
if (this.multiKickerMagnitude > 0)
|
||||
if (this.multiKickerMagnitude > 0) {
|
||||
return multiKickerMagnitude;
|
||||
}
|
||||
boolean hasK1 = costsPaid.contains(OptionalCost.Kicker1);
|
||||
return hasK1 == costsPaid.contains(OptionalCost.Kicker2) ? (hasK1 ? 2 : 0) : 1;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -51,7 +51,7 @@ public final class CardUtil {
|
||||
"Enchant", "Protection", "Cumulative upkeep", "Equip", "Buyback",
|
||||
"Cycling", "Echo", "Kicker", "Flashback", "Madness", "Morph",
|
||||
"Affinity", "Entwine", "Splice", "Ninjutsu",
|
||||
"Transute", "Replicate", "Recover", "Suspend", "Aura swap",
|
||||
"Transmute", "Replicate", "Recover", "Suspend", "Aura swap",
|
||||
"Fortify", "Transfigure", "Champion", "Evoke", "Prowl",
|
||||
"Reinforce", "Unearth", "Level up", "Miracle", "Overload",
|
||||
"Scavenge", "Bestow", "Outlast").build();
|
||||
|
||||
@@ -31,6 +31,8 @@ import forge.util.maps.MapToAmount;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* ManaCostBeingPaid class.
|
||||
@@ -215,6 +217,20 @@ public class ManaCostBeingPaid {
|
||||
return unpaidShards.isEmpty();
|
||||
}
|
||||
|
||||
public final void setXManaCostPaid(final int xPaid, final String xColor) {
|
||||
int xCost = xPaid * cntX;
|
||||
cntX = 0;
|
||||
|
||||
ManaCostShard increaseShard;
|
||||
if (StringUtils.isEmpty(xColor)) {
|
||||
increaseShard = ManaCostShard.COLORLESS;
|
||||
}
|
||||
else {
|
||||
increaseShard = ManaCostShard.valueOf(MagicColor.fromName(xColor));
|
||||
}
|
||||
unpaidShards.add(increaseShard, xCost);
|
||||
}
|
||||
|
||||
public final void increaseColorlessMana(final int manaToAdd) {
|
||||
increaseShard(ManaCostShard.COLORLESS, manaToAdd);
|
||||
}
|
||||
|
||||
@@ -131,8 +131,9 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
public final AbilityManaPart getManaPartRecursive() {
|
||||
SpellAbility tail = this;
|
||||
while (tail != null) {
|
||||
if(tail.manaPart != null)
|
||||
if (tail.manaPart != null) {
|
||||
return tail.manaPart;
|
||||
}
|
||||
tail = tail.getSubAbility();
|
||||
}
|
||||
return null;
|
||||
@@ -140,14 +141,17 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
|
||||
public final boolean isManaAbility() {
|
||||
// Check whether spell or ability first
|
||||
if (this.isSpell())
|
||||
if (this.isSpell()) {
|
||||
return false;
|
||||
}
|
||||
// without a target
|
||||
if (this.usesTargeting()) return false;
|
||||
if (getRestrictions() != null && getRestrictions().getPlaneswalker())
|
||||
if (this.usesTargeting()) { return false; }
|
||||
if (getRestrictions() != null && getRestrictions().getPlaneswalker()) {
|
||||
return false; //Loyalty ability, not a mana ability.
|
||||
if (this.isWrapper() && ((WrappedAbility) this).getTrigger().getMode() != TriggerType.TapsForMana)
|
||||
}
|
||||
if (this.isWrapper() && ((WrappedAbility) this).getTrigger().getMode() != TriggerType.TapsForMana) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return getManaPartRecursive() != null;
|
||||
}
|
||||
@@ -157,7 +161,22 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
}
|
||||
|
||||
public final String getSVar(final String name) {
|
||||
return sVars.get(name) != null ? sVars.get(name) : "";
|
||||
String var = sVars.get(name);
|
||||
if (var == null) {
|
||||
var = "";
|
||||
}
|
||||
return var;
|
||||
}
|
||||
|
||||
public final Integer getSVarInt(final String name) {
|
||||
String var = sVars.get(name);
|
||||
if (var != null) {
|
||||
try {
|
||||
return Integer.parseInt(var);
|
||||
}
|
||||
catch (Exception e) {}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public final void setSVar(final String name, final String value) {
|
||||
@@ -298,18 +317,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
public boolean isSpell() { return false; }
|
||||
public boolean isAbility() { return true; }
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* isMultiKicker.
|
||||
* </p>
|
||||
*
|
||||
* @return a boolean.
|
||||
*/
|
||||
public boolean isMultiKicker() {
|
||||
return this.multiKickerManaCost != null && !this.isAnnouncing("Multikicker");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* setIsMorphUp.
|
||||
@@ -380,14 +387,14 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
}
|
||||
|
||||
public String getParamOrDefault(String key, String defaultValue) {
|
||||
return mapParams == null || !mapParams.containsKey(key) ? defaultValue : mapParams.get(key);
|
||||
return mapParams.containsKey(key) ? mapParams.get(key) : defaultValue;
|
||||
}
|
||||
|
||||
public String getParam(String key) {
|
||||
return mapParams == null ? null : mapParams.get(key);
|
||||
return mapParams.get(key);
|
||||
}
|
||||
public boolean hasParam(String key) {
|
||||
return mapParams == null ? false : mapParams.containsKey(key);
|
||||
return mapParams.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -395,9 +402,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
* @param mapParams
|
||||
*/
|
||||
public void copyParamsToMap(Map<String, String> mapParams) {
|
||||
if (null != this.mapParams) {
|
||||
mapParams.putAll(this.mapParams);
|
||||
}
|
||||
mapParams.putAll(this.mapParams);
|
||||
}
|
||||
|
||||
// If this is not null, then ability was made in a factory
|
||||
@@ -1127,8 +1132,9 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
}
|
||||
|
||||
String[] validTgt = tr.getValidTgts();
|
||||
if (entity instanceof GameEntity && !((GameEntity) entity).isValid(validTgt, this.getActivatingPlayer(), this.getHostCard()))
|
||||
if (entity instanceof GameEntity && !((GameEntity) entity).isValid(validTgt, this.getActivatingPlayer(), this.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Restrictions coming from target
|
||||
@@ -1298,7 +1304,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
while (null != parent.getParent()) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
@@ -1351,15 +1356,32 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
*/
|
||||
public boolean isAnnouncing(String variable) {
|
||||
String announce = getParam("Announce");
|
||||
if (StringUtils.isBlank(announce)) return false;
|
||||
if (StringUtils.isBlank(announce)) { return false; }
|
||||
|
||||
String[] announcedOnes = TextUtil.split(announce, ',');
|
||||
for(String a : announcedOnes) {
|
||||
if( a.trim().equalsIgnoreCase(variable))
|
||||
for (String a : announcedOnes) {
|
||||
if (a.trim().equalsIgnoreCase(variable)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addAnnounceVar(String variable) {
|
||||
String announce = getParam("Announce");
|
||||
if (StringUtils.isBlank(announce)) {
|
||||
mapParams.put("Announce", variable);
|
||||
return;
|
||||
}
|
||||
String[] announcedOnes = TextUtil.split(announce, ',');
|
||||
for (String a : announcedOnes) {
|
||||
if (a.trim().equalsIgnoreCase(variable)) {
|
||||
return; //don't add announce variable that already exists
|
||||
}
|
||||
}
|
||||
mapParams.put("Announce", announce + ";" + variable);
|
||||
}
|
||||
|
||||
public boolean isXCost() {
|
||||
CostPartMana cm = payCosts != null ? getPayCosts().getCostMana() : null;
|
||||
return cm != null && cm.getAmountOfX() > 0;
|
||||
@@ -1486,10 +1508,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
targetChosen.add(card);
|
||||
|
||||
final String desc;
|
||||
|
||||
if (!card.isFaceDown()) {
|
||||
desc = this.getHostCard().getName() + " - targeting " + card;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
desc = this.getHostCard().getName() + " - targeting Morph(" + card.getUniqueNumber() + ")";
|
||||
}
|
||||
this.setStackDescription(desc);
|
||||
@@ -1532,7 +1554,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
return ImmutableList.<Card>of();
|
||||
}
|
||||
|
||||
|
||||
public SpellAbility getSATargetingCard() {
|
||||
return targetChosen.isTargetingAnyCard() ? this : getParentTargetingCard();
|
||||
}
|
||||
@@ -1543,8 +1564,9 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
parent = ((WrappedAbility) parent).getWrappedAbility();
|
||||
}
|
||||
while (parent != null) {
|
||||
if (parent.targetChosen.isTargetingAnyCard())
|
||||
if (parent.targetChosen.isTargetingAnyCard()) {
|
||||
return parent;
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
return null;
|
||||
@@ -1674,15 +1696,21 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
final String[] incR = restriction.split("\\.", 2);
|
||||
|
||||
if (incR[0].equals("Spell")) {
|
||||
if (!this.isSpell())
|
||||
if (!this.isSpell()) {
|
||||
return false;
|
||||
} else if (incR[0].equals("Triggered")) {
|
||||
if (!this.isTrigger())
|
||||
}
|
||||
}
|
||||
else if (incR[0].equals("Triggered")) {
|
||||
if (!this.isTrigger()) {
|
||||
return false;
|
||||
} else if (incR[0].equals("Activated")) {
|
||||
if (!(this instanceof AbilityActivated))
|
||||
}
|
||||
}
|
||||
else if (incR[0].equals("Activated")) {
|
||||
if (!(this instanceof AbilityActivated)) {
|
||||
return false;
|
||||
} else { //not a spell/ability type
|
||||
}
|
||||
}
|
||||
else { //not a spell/ability type
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1811,5 +1839,4 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
this.subAbility.setIntrinsic(i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -243,11 +243,6 @@ public class WrappedAbility extends Ability implements ISpellAbility {
|
||||
return sa.isFlashBackAbility();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMultiKicker() {
|
||||
return sa.isMultiKicker();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSpell() {
|
||||
return sa.isSpell();
|
||||
|
||||
@@ -332,27 +332,15 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
// TODO: make working triggered ability
|
||||
sp.setTotalManaSpent(totManaSpent);
|
||||
AbilityUtils.resolve(sp);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
for (OptionalCost s : sp.getOptionalCosts()) {
|
||||
source.addOptionalCostPaid(s);
|
||||
}
|
||||
if (sp.isCopied()) {
|
||||
si = this.push(sp);
|
||||
} else {
|
||||
if (sp.isMultiKicker()) {
|
||||
final Cost costMultikicker = new Cost(sp.getMultiKickerManaCost(), false);
|
||||
boolean hasPaid = false;
|
||||
do {
|
||||
int mkMagnitude = source.getKickerMagnitude();
|
||||
String prompt = String.format("Multikicker for %s\r\nTimes Kicked: %d\r\n", source, mkMagnitude );
|
||||
hasPaid = activator.getController().payManaOptional(source, costMultikicker, sp, prompt, ManaPaymentPurpose.Multikicker);
|
||||
if (hasPaid) {
|
||||
source.addMultiKickerMagnitude(1);
|
||||
totManaSpent += sp.getPayingMana().size();
|
||||
// TODO: paying mana is replaced by multikicker cost, this should be fixed in the future
|
||||
}
|
||||
} while( hasPaid );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (sp.isSpell() && source.isCreature() && Iterables.any(activator.getCardsIn(ZoneType.Battlefield),
|
||||
CardPredicates.hasKeyword("As an additional cost to cast creature spells," +
|
||||
" you may pay any amount of mana. If you do, that creature enters " +
|
||||
@@ -390,33 +378,34 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
|
||||
// The ability is added to stack HERE
|
||||
si = this.push(sp);
|
||||
|
||||
|
||||
if (sp.isSpell() && (source.hasStartOfKeyword("Replicate")
|
||||
|| ((source.isInstant() || source.isSorcery()) && Iterables.any(activator.getCardsIn(ZoneType.Battlefield),
|
||||
CardPredicates.hasKeyword("Each instant and sorcery spell you cast has replicate. The replicate cost is equal to its mana cost."))))) {
|
||||
int magnitude = 0;
|
||||
// TODO: convert multikicker/replicate support in abCost so this
|
||||
// doesn't happen here
|
||||
|
||||
final Cost costReplicate = new Cost(source.getManaCost(), false);
|
||||
boolean hasPaid = false;
|
||||
int replicateCMC = source.getManaCost().getCMC();
|
||||
do {
|
||||
String prompt = String.format("Replicate for %s\r\nTimes Replicated: %d\r\n", source, magnitude);
|
||||
hasPaid = activator.getController().payManaOptional(source, costReplicate, sp, prompt, ManaPaymentPurpose.Replicate);
|
||||
if (hasPaid) {
|
||||
magnitude++;
|
||||
totManaSpent += replicateCMC;
|
||||
}
|
||||
} while( hasPaid );
|
||||
Integer magnitude = sp.getSVarInt("Replicate");
|
||||
if (magnitude == null) {
|
||||
magnitude = 0;
|
||||
final Cost costReplicate = new Cost(source.getManaCost(), false);
|
||||
boolean hasPaid = false;
|
||||
int replicateCMC = source.getManaCost().getCMC();
|
||||
do {
|
||||
String prompt = String.format("Replicate for %s\r\nTimes Replicated: %d\r\n", source, magnitude);
|
||||
hasPaid = activator.getController().payManaOptional(source, costReplicate, sp, prompt, ManaPaymentPurpose.Replicate);
|
||||
if (hasPaid) {
|
||||
magnitude++;
|
||||
totManaSpent += replicateCMC;
|
||||
}
|
||||
} while (hasPaid);
|
||||
}
|
||||
|
||||
// Replicate Trigger
|
||||
String effect = String.format("AB$ CopySpellAbility | Cost$ 0 | Defined$ SourceFirstSpell | Amount$ %d", magnitude);
|
||||
SpellAbility sa = AbilityFactory.getAbility(effect, source);
|
||||
sa.setDescription("Replicate - " + source);
|
||||
sa.setTrigger(true);
|
||||
sa.setCopied(true);
|
||||
addSimultaneousStackEntry(sa);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user