Merge remote-tracking branch 'core/master' into AdventureModePort

This commit is contained in:
Anthony Calosa
2022-02-08 12:56:47 +08:00
11 changed files with 112 additions and 40 deletions

View File

@@ -98,7 +98,7 @@ public abstract class SpellAbilityEffect {
sb.append(" (Targeting: ").append(sa.getTargets()).append(")");
}
} else if (!"None".equalsIgnoreCase(stackDesc)) { // by typing "none" they want to suppress output
makeSpellDescription(sa, sb, stackDesc);
tokenizeString(sa, sb, stackDesc);
}
} else {
final String condDesc = sa.getParam("ConditionDescription");
@@ -155,7 +155,7 @@ public abstract class SpellAbilityEffect {
* {@link Player}, {@link SpellAbility}, and {@link Card}
* objects.
*/
private static void makeSpellDescription(final SpellAbility sa, final StringBuilder sb, final String stackDesc) {
public static void tokenizeString(final SpellAbility sa, final StringBuilder sb, final String stackDesc) {
final StringTokenizer st = new StringTokenizer(stackDesc, "{}", true);
boolean isPlainText = true;

View File

@@ -4,6 +4,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import forge.game.*;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
@@ -16,11 +17,6 @@ import com.google.common.collect.Maps;
import forge.GameCommand;
import forge.card.CardStateName;
import forge.card.CardType;
import forge.game.Game;
import forge.game.GameActionUtil;
import forge.game.GameEntity;
import forge.game.GameEntityCounterTable;
import forge.game.GameLogEntryType;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
@@ -81,12 +77,6 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
final StringBuilder sb = new StringBuilder();
final Card host = sa.getHostCard();
if (!(sa instanceof AbilitySub)) {
sb.append(" -");
}
sb.append(" ");
// Player whose cards will change zones
List<Player> fetchers = null;
if (sa.hasParam("DefinedPlayer")) {
@@ -131,9 +121,14 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
String type = "card";
if (sa.hasParam("ChangeTypeDesc")) {
type = sa.getParam("ChangeTypeDesc");
}
else if (sa.hasParam("ChangeType")) {
type = sa.getParam("ChangeType");
if (type.contains("{")) {
final StringBuilder typesb = new StringBuilder();
SpellAbilityEffect.tokenizeString(sa, typesb, type);
type = typesb.toString();
}
} else if (sa.hasParam("ChangeType")) {
final String ct = sa.getParam("ChangeType");
type = CardType.CoreType.isValidEnum(ct) ? ct.toLowerCase() : ct;
}
final int num = sa.hasParam("ChangeNum") ? AbilityUtils.calculateAmount(host,
@@ -155,28 +150,26 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
sb.append(chooserNames);
sb.append(" search").append(choosers.size() > 1 ? " " : "es ");
sb.append(fetchPlayer).append(fetchPlayer.equals(chooserNames) ? "'s " : " ");
sb.append("library for ").append(num).append(" ");
sb.append(type).append(num > 1 ? "s" : "");
sb.append("library for ").append(Lang.nounWithNumeralExceptOne(num, type + " card")).append(", ");
if (!sa.hasParam("NoReveal")) {
if (choosers.size() == 1) {
sb.append(num > 1 ? ", reveals those cards," : ", reveals that card,");
sb.append(num > 1 ? "reveals them, " : "reveals it, ");
} else {
sb.append(num > 1 ? ", reveal those cards," : ", reveal that card,");
sb.append(num > 1 ? "reveal them, " : "reveal it, ");
}
}
sb.append(" and ");
if (destination.equals("Exile")) {
if (num == 1) {
sb.append("exiles that card ");
sb.append("exiles it");
} else {
sb.append("exiles those cards ");
sb.append("exiles them");
}
} else {
if (num == 1) {
sb.append("puts that card ");
sb.append("puts it ");
} else {
sb.append("puts those cards ");
sb.append("puts them ");
}
if (destination.equals("Battlefield")) {
@@ -187,27 +180,23 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (sa.hasParam("GainControl")) {
sb.append(" under ").append(chooserNames).append("'s control");
}
sb.append(".");
}
if (destination.equals("Hand")) {
if (num == 1) {
sb.append("into its owner's hand.");
sb.append("into its owner's hand");
} else {
sb.append("into their owner's hand.");
sb.append("into their owner's hand");
}
}
if (destination.equals("Graveyard")) {
if (num == 1) {
sb.append("into its owner's graveyard.");
sb.append("into its owner's graveyard");
} else {
sb.append("into their owner's graveyard.");
sb.append("into their owner's graveyard");
}
}
}
sb.append(" Then shuffle that library.");
sb.append(", then shuffles.");
} else if (origin.equals("Sideboard")) {
sb.append(chooserNames);
//currently Reveal is always True in ChangeZone

View File

@@ -20,6 +20,7 @@ package forge.game.ability.effects;
import java.util.List;
import forge.util.Lang;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.mutable.MutableBoolean;
import forge.game.Game;
@@ -37,12 +38,13 @@ public class TokenEffect extends TokenEffectBase {
protected String getStackDescription(SpellAbility sa) {
if (sa.hasParam("SpellDescription")) {
String desc = sa.getParam("SpellDescription");
if (desc.startsWith("Create")) {
if (StringUtils.containsIgnoreCase(desc,"Create")) {
final Card host = sa.getHostCard();
final List<Player> creators = AbilityUtils.getDefinedPlayers(host, sa.getParamOrDefault("TokenOwner",
"You"), sa);
String start = Lang.joinHomogenous(creators) + (creators.size() == 1 ? " creates" : " create");
desc = desc.replace("Create",start);
String create = desc.contains("Create") ? "Create" : "create";
desc = desc.replace(create, start);
}
return desc;
}

View File

@@ -0,0 +1,12 @@
Name:Anchor to Reality
ManaCost:2 U U
Types:Sorcery
A:SP$ ChangeZone | Cost$ 2 U U Sac<1/Artifact;Creature/artifact or creature> | Origin$ Library | Destination$ Battlefield | ChangeType$ Equipment,Vehicle | ChangeTypeDesc$ Equipment or Vehicle card | ChangeNum$ 1 | RememberChanged$ True | SubAbility$ DBScry | SpellDescription$ Search your library for an Equipment or Vehicle card, put that card onto the battlefield, then shuffle.
SVar:DBScry:DB$ Scry | ConditionDefined$ Remembered | ConditionPresent$ Card | ScryNum$ X | SubAbility$ DBCleanup | SpellDescription$ If it has mana value less than the sacrificed permanent's mana value, scry 2.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$Compare Y LTZ.2.0
SVar:Y:Remembered$CardManaCost
SVar:Z:Sacrificed$CardManaCost
DeckNeeds:Type$Artifact|Creature|Equipment|Vehicle
AI:RemoveDeck:Random
Oracle:As an additional cost to cast this spell, sacrifice an artifact or creature.\nSearch your library for an Equipment or Vehicle card, put that card onto the battlefield, then shuffle. If it has mana value less than the sacrificed permanent's mana value, scry 2.

View File

@@ -0,0 +1,8 @@
Name:Blade of the Oni
ManaCost:1 B
Types:Artifact Creature Equipment Demon
PT:3/1
K:Menace
K:Reconfigure:2 B B
S:Mode$ Continuous | Affected$ Creature.EquippedBy | SetPower$ 5 | SetToughness$ 5 | AddKeyword$ Menace | AddType$ Demon | AddColor$ Black | Description$ Equipped creature has base power and toughness 5/5, has menace, and is a black Demon in addition to its other colors and types.
Oracle:Menace\nEquipped creature has base power and toughness 5/5, has menace, and is a black Demon in addition to its other colors and types.\nReconfigure {2}{B}{B} ({2}{B}{B}: Attach to target creature you control; or unattach from a creature. Reconfigure only as a sorcery. While attached, this isn't a creature.)

View File

@@ -0,0 +1,6 @@
Name:Fang of Shigeki
ManaCost:G
Types:Enchantment Creature Snake Ninja
PT:1/1
K:Deathtouch
Oracle:Deathtouch

View File

@@ -0,0 +1,28 @@
Name:Inventive Iteration
ManaCost:3 U
Types:Enchantment Saga
K:Saga:3:DBReturn1,DBReturn2,DBTransform
SVar:DBReturn1:DB$ ChangeZone | ValidTgts$ Creature,Planeswalker | TargetMin$ 0 | TargetMax$ 1 | Origin$ Battlefield | Destination$ Hand | TgtPrompt$ Select target creature or planeswalker | SpellDescription$ Return up to one target creature or planeswalker to its owner's hand.
SVar:DBReturn2:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | ChangeType$ Artifact | ChangeNum$ 1 Mandatory$ True | RememberChanged$ True | SubAbility$ DBDraw | SpellDescription$ Return an artifact card from your graveyard to your hand. If you can't, draw a card.
SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ 1
SVar:DBTransform:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | SubAbility$ DBReturn | SpellDescription$ Exile this Saga, then return it to the battlefield transformed under your control.
SVar:DBReturn:DB$ ChangeZone | Defined$ Remembered | Origin$ Exile | Destination$ Battlefield | Transformed$ True | GainControl$ True | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
AlternateMode:DoubleFaced
DeckHints:Type$Creature|Planeswalker|Artifact
DeckHas:Ability$Graveyard
Oracle:(As this Saga enters and after your draw step, add a lore counter.)\nI — Return up to one target creature or planeswalker to its owner's hand.\nII — Return an artifact card from your graveyard to your hand. If you can't, draw a card.\nIII — Exile this Saga, then return it to the battlefield transformed under your control.
ALTERNATE
Name:Living Breakthrough
ManaCost:no cost
Colors:blue
Types:Enchantment Creature Moonfolk
PT:3/3
K:Flying
T:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigEffect | TriggerDescription$ Whenever you cast a spell, your opponents can't cast spells with the same mana value as that spell until your next turn.
SVar:TrigEffect:DB$ Effect | StaticAbilities$ OppCantCast | RememberObjects$ TriggeredCard | Duration$ UntilYourNextTurn
SVar:OppCantCast:Mode$ CantBeCast | ValidCard$ Card.cmcEQX | Caster$ Opponent | Description$ Your opponents can't cast spells with the same mana value as that spell until your next turn.
SVar:X:Remembered$CardManaCost
Oracle:Flying\nWhenever you cast a spell, your opponents can't cast spells with the same mana value as that spell until your next turn.

View File

@@ -0,0 +1,6 @@
Name:Invoke the Winds
ManaCost:1 U U U U
Types:Sorcery
A:SP$ GainControl | ValidTgts$ Artifact,Creature | TgtPrompt$ Select target artifact or creature | SubAbility$ DBUntap | SpellDescription$ Gain control of target artifact or creature.
SVar:DBUntap:DB$ Untap | Defined$ Targeted | SpellDescription$ Untap it.
Oracle:Gain control of target artifact or creature. Untap it.

View File

@@ -0,0 +1,12 @@
Name:March of Burgeoning Life
ManaCost:X G
Types:Instant
A:SP$ Pump | AnnounceTitle$ how many green cards to exile | Announce$ Exiled | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Creature.cmcLTX | TgtPrompt$ Choose target creature with mana value less than X | SubAbility$ DBSearch | StackDescription$ None | SpellDescription$ Choose target creature with mana value less than X. Search your library for a creature card with the same name as that creature, put it onto the battlefield tapped, then shuffle.
SVar:DBSearch:DB$ ChangeZone | Origin$ Library | Destination$ Battlefield | ChangeType$ Targeted.Creature+sameName | ChangeTypeDesc$ creature card with the same name as {c:Targeted} | ChangeNum$ 1 | Mandatory$ True | Tapped$ True
S:Mode$ RaiseCost | ValidCard$ Card.Self | Type$ Spell | Cost$ ExileFromHand<Y/Card.Green/green cards> | EffectZone$ All | Description$ As an additional cost to cast this spell, you may exile any number of green cards from your hand. This spell costs {2} less to cast for each card exiled this way.
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ Z | EffectZone$ All | Relative$ True | Secondary$ True | Description$ This spell costs {2} less to cast for each card exiled this way.
SVar:X:Count$xPaid
SVar:Y:SVar$Exiled
SVar:Z:SVar$Y/Times.2
SVar:Exiled:Number$0
Oracle:As an additional cost to cast this spell, you may exile any number of green cards from your hand. This spell costs {2} less to cast for each card exiled this way.\nChoose target creature with mana value less than X. Search your library for a creature card with the same name as that creature, put it onto the battlefield tapped, then shuffle.

View File

@@ -0,0 +1,10 @@
Name:Prosperous Thief
ManaCost:2 U
Types:Creature Human Ninja
PT:3/2
K:Ninjutsu:1 U
T:Mode$ DamageDoneOnce | ValidSource$ Creature.Ninja+YouCtrl,Creature.Rogue+YouCtrl | TriggerZones$ Battlefield | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigToken | TriggerDescription$ Whenever one or more Ninja or Rogue creatures you control deal combat damage to a player, create a Treasure token. (It's an artifact with "{T}, Sacrifice this artifact: Add one mana of any color.")
SVar:TrigToken:DB$ Token | TokenScript$ c_a_treasure_sac
DeckHints:Type$Ninja|Rogue
DeckHas:Ability$Token|Sacrifice & Type$Artifact|Treasure
Oracle:Ninjutsu {1}{U} ({1}{U}, Return an unblocked attacker you control to hand: Put this card onto the battlefield from your hand tapped and attacking.)\nWhenever one or more Ninja or Rogue creatures you control deal combat damage to a player, create a Treasure token. (It's an artifact with "{T}, Sacrifice this artifact: Add one mana of any color.")

View File

@@ -3,10 +3,9 @@ ManaCost:2
Types:Artifact Vehicle
PT:4/4
K:etbCounter:CHARGE:3
A:AB$ Draw | Cost$ 2 T SubCounter<1/CHARGE> | SubAbility$ DBTreasure | SpellDescription$ Draw a card.
SVar:DBTreasure:DB$ Token | TokenScript$ c_a_treasure_sac | ConditionDefined$ Self | ConditionPresent$ Card.counters_EQ0_CHARGE | SubAbility$ DBPilot | SpellDescription$ Then if there are no charge counters on CARDNAME, create a Treasure token
SVar:DBPilot:DB$ Token | TokenScript$ c_1_1_pilot_crewbuff | ConditionDefined$ Self | ConditionPresent$ Card.counters_EQ0_CHARGE | SpellDescription$ and a 1/1 colorless Pilot creature token with "This creature crews Vehicles as though its power were 2 greater."
A:AB$ Draw | Cost$ 2 T SubCounter<1/CHARGE> | SubAbility$ DBToken | SpellDescription$ Draw a card.
SVar:DBToken:DB$ Token | TokenScript$ c_a_treasure_sac,c_1_1_pilot_crewbuff | ConditionDefined$ Self | ConditionPresent$ Card.counters_EQ0_CHARGE | SubAbility$ DBPilot | SpellDescription$ Then if there are no charge counters on CARDNAME, create a Treasure token and a 1/1 colorless Pilot creature token with "This creature crews Vehicles as though its power were 2 greater."
K:Crew:3
DeckHas:Ability$Counters|Token|Sacrifice & Type$Pilot
DeckHas:Ability$Counters|Token|Sacrifice & Type$Pilot|Treasure
DeckHints:Type$Vehicle
Oracle:Reckoner Bankbuster enters the battlefield with three charge counters on it.\n{2}, {T}, Remove a charge counter from Reckoner Bankbuster: Draw a card. Then if there are no charge counters on Reckoner Bankbuster, create a Treasure token and a 1/1 colorless Pilot creature token with "This creature crews Vehicles as though its power were 2 greater."\nCrew 3