Skip to content

Commit

Permalink
Merge branch 'Card-Forge:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
jjayers99 authored Jan 8, 2024
2 parents c98bf85 + dccfee6 commit 81de9a6
Show file tree
Hide file tree
Showing 17 changed files with 105 additions and 23 deletions.
11 changes: 5 additions & 6 deletions forge-ai/src/main/java/forge/ai/ability/CharmAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,6 @@ protected boolean checkApiLogic(Player ai, SpellAbility sa) {
min = sa.hasParam("MinCharmNum") ? AbilityUtils.calculateAmount(source, sa.getParam("MinCharmNum"), sa) : num;
}

// only randomize if not all possible together
if (num < choices.size() || source.hasKeyword(Keyword.ESCALATE)) {
Collections.shuffle(choices);
}

boolean timingRight = sa.isTrigger(); //is there a reason to play the charm now?

// Reset the chosen list otherwise it will be locked in forever by earlier calls
Expand All @@ -51,11 +46,15 @@ protected boolean checkApiLogic(Player ai, SpellAbility sa) {
if (!ai.equals(sa.getActivatingPlayer())) {
// This branch is for "An Opponent chooses" Charm spells from Alliances
// Current just choose the first available spell, which seem generally less disastrous for the AI.
//return choices.subList(0, 1);
chosenList = choices.subList(1, choices.size());
} else if ("Triskaidekaphobia".equals(ComputerUtilAbility.getAbilitySourceName(sa))) {
chosenList = chooseTriskaidekaphobia(choices, ai);
} else {
// only randomize if not all possible together
if (num < choices.size() || source.hasKeyword(Keyword.ESCALATE)) {
Collections.shuffle(choices);
}

/*
* The generic chooseOptionsAi uses canPlayAi() to determine good choices
* which means most "bonus" effects like life-gain and random pumps will
Expand Down
1 change: 1 addition & 0 deletions forge-game/src/main/java/forge/game/GameActionUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,7 @@ public static void rollbackAbility(SpellAbility ability, final Zone fromZone, fi
if (ability.getApi() == ApiType.Charm) {
// reset chain
ability.setSubAbility(null);
ability.setChosenList(null);
}

ability.clearTargets();
Expand Down
15 changes: 9 additions & 6 deletions forge-game/src/main/java/forge/game/ability/AbilityUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -1050,7 +1050,7 @@ else if (defined.startsWith("Remembered")) {
addPlayer(card.getRemembered(), defined, players);
}
else if (defined.startsWith("Imprinted")) {
addPlayer(Lists.newArrayList(card.getImprintedCards()), defined, players);
addPlayer(card.getImprintedCards(), defined, players);
}
else if (defined.startsWith("EffectSource")) {
Card root = findEffectRoot(card);
Expand Down Expand Up @@ -1093,9 +1093,9 @@ else if (defined.startsWith("Triggered") && sa instanceof SpellAbility) {
o = ((SpellAbility) c).getActivatingPlayer();
} else if (c instanceof Iterable<?>) { // For merged permanent
if (orCont) {
addPlayer(ImmutableList.copyOf(Iterables.filter((Iterable<Object>)c, Player.class)), "", players);
addPlayer(Iterables.filter((Iterable<Object>)c, Player.class), "", players);
}
addPlayer(ImmutableList.copyOf(Iterables.filter((Iterable<Object>)c, Card.class)), "Controller", players);
addPlayer(Iterables.filter((Iterable<Object>)c, Card.class), "Controller", players);
}
}
else if (defParsed.endsWith("Opponent")) {
Expand Down Expand Up @@ -1205,14 +1205,17 @@ else if (defined.equals("AttackingPlayer")) {
else if (defined.equals("DefendingPlayer")) {
players.add(game.getCombat().getDefendingPlayerRelatedTo(card));
}
else if (defined.equals("ChoosingPlayer")) {
players.add(((SpellAbility) sa).getRootAbility().getChoosingPlayer());
}
else if (defined.equals("ChosenPlayer")) {
final Player p = card.getChosenPlayer();
if (p != null) {
players.add(p);
}
}
else if (defined.startsWith("ChosenCard")) {
addPlayer(Lists.newArrayList(card.getChosenCards()), defined, players);
addPlayer(card.getChosenCards(), defined, players);
}
else if (defined.equals("SourceController")) {
players.add(sa.getHostCard().getController());
Expand Down Expand Up @@ -3053,11 +3056,11 @@ public static final String getSVar(final CardTraitBase ability, final String sVa
return applyAbilityTextChangeEffects(val, ability);
}

private static void addPlayer(Iterable<Object> objects, final String def, FCollection<Player> players) {
private static void addPlayer(Iterable<?> objects, final String def, FCollection<Player> players) {
addPlayer(objects, def, players, false);
}

private static void addPlayer(Iterable<Object> objects, final String def, FCollection<Player> players, boolean skipRemembered) {
private static void addPlayer(Iterable<?> objects, final String def, FCollection<Player> players, boolean skipRemembered) {
for (Object o : objects) {
if (o instanceof Player) {
final Player p = (Player) o;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ public static boolean makeChoices(SpellAbility sa) {
//String choosers = sa.getParam("Chooser");
FCollection<Player> opponents = activator.getOpponents(); // all cards have Choser$ Opponent, so it's hardcoded here
chooser = activator.getController().chooseSingleEntityForEffect(opponents, sa, "Choose an opponent", null);
source.setChosenPlayer(chooser);
sa.setChoosingPlayer(chooser);
}

List<AbilitySub> chosen = chooser.getController().chooseModeForAbility(sa, choices, min, num, canRepeat);
Expand Down
6 changes: 3 additions & 3 deletions forge-game/src/main/java/forge/game/card/CardFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public final static Card copyCard(final Card in, boolean assignNewId) {
out = assignNewId ? getCard(in.getPaperCard(), in.getOwner(), in.getGame())
: getCard(in.getPaperCard(), in.getOwner(), in.getId(), in.getGame());
} else { // token
out = CardFactory.copyStats(in, in.getController(), assignNewId);
out = copyStats(in, in.getController(), assignNewId);
out.setToken(true);

// need to copy this values for the tokens
Expand Down Expand Up @@ -128,7 +128,7 @@ private final static Card copySpellHost(final SpellAbility sourceSA, final Spell
int id = game.nextCardId();

// need to create a physical card first, i need the original card faces
final Card copy = CardFactory.getCard(original.getPaperCard(), controller, id, game);
final Card copy = getCard(original.getPaperCard(), controller, id, game);

if (original.isTransformable()) {
// 707.8a If an effect creates a token that is a copy of a transforming permanent or a transforming double-faced card not on the battlefield,
Expand Down Expand Up @@ -530,7 +530,7 @@ public static Card copyStats(final Card in, final Player newOwner, boolean assig
c.setSetCode(in.getSetCode());

for (final CardStateName state : in.getStates()) {
CardFactory.copyState(in, state, c, state);
copyState(in, state, c, state);
}

c.setState(in.getCurrentStateName(), false);
Expand Down
13 changes: 11 additions & 2 deletions forge-game/src/main/java/forge/game/spellability/SpellAbility.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,14 @@ public static class EmptySa extends SpellAbility {
// choices for constructor isPermanent argument
private String originalDescription = "", description = "";
private String originalStackDescription = "", stackDescription = "";
private ManaCost multiKickerManaCost;

private Player activatingPlayer;
private Player targetingPlayer;
private Player choosingPlayer;
private Pair<Long, Player> controlledByPlayer;

private ManaCostBeingPaid manaCostBeingPaid;
private ManaCost multiKickerManaCost;
private int spentPhyrexian = 0;
private int paidLifeAmount = 0;

Expand Down Expand Up @@ -147,7 +150,6 @@ public static class EmptySa extends SpellAbility {
private TreeBasedTable<String, Boolean, CardCollection> paidLists = TreeBasedTable.create();

private EnumMap<AbilityKey, Object> triggeringObjects = AbilityKey.newMap();

private EnumMap<AbilityKey, Object> replacingObjects = AbilityKey.newMap();

private final List<String> pipsToReduce = new ArrayList<>();
Expand Down Expand Up @@ -481,6 +483,13 @@ public void setTargetingPlayer(Player targetingPlayer0) {
targetingPlayer = targetingPlayer0;
}

public Player getChoosingPlayer() {
return choosingPlayer;
}
public void setChoosingPlayer(Player choosingPlayer0) {
choosingPlayer = choosingPlayer0;
}

/**
* @return returns who controls the controller of this sa when it is resolving (for Word of Command effect). Null means not being controlled by other
*/
Expand Down
4 changes: 3 additions & 1 deletion forge-gui/res/blockdata/blocks.txt
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,6 @@ March of the Machine Jumpstart, -/2/MOM, Meta-Choose(S(MOM Brood 1)Brood 1;S(MOM
The Lord of the Rings: Tales of Middle-earth, 3/6/LTR, LTR
The Lord of the Rings: Tales of Middle-earth Jumpstart, -/2/LTR, Meta-Choose(S(LTR Courageous 1)Courageous 1;S(LTR Courageous 2)Courageous 2;S(LTR Tricksy 1)Tricksy 1;S(LTR Tricksy 2)Tricksy 2;S(LTR Mordor 1)Mordor 1;S(LTR Mordor 2)Mordor 1;S(LTR Marauders 1)Marauders 1;S(LTR Marauders 2)Marauders 1;S(LTR Journey 1)Journey 1;S(LTR Journey 2)Journey 2)Themes
Wilds of Eldraine, 3/6/WOE, WOE
The Lost Caverns of Ixalan, 3/6/LCI, LCI
Alchemy: Eldraine,3/6/WOE, YWOE
The Lost Caverns of Ixalan, 3/6/LCI, LCI
Alchemy: Ixalan,3/6/LCI, YLCI
11 changes: 11 additions & 0 deletions forge-gui/res/cardsfolder/e/ensnared_by_the_mara.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Name:Ensnared by the Mara
ManaCost:2 R R
Types:Sorcery
A:SP$ VillainousChoice | Defined$ Opponent | Choices$ DBDig,DBDamage | SpellDescription$ Each opponent faces a villainous choice — They exile cards from the top of their library until they exile a nonland card, then you may cast that card without paying its mana cost, or that player exiles the top four cards of their library and CARDNAME deals damage equal to the total mana value of those exiled cards to that player.
SVar:DBDig:DB$ DigUntil | Defined$ Remembered | Valid$ Card.nonLand | FoundDestination$ Exile | RevealedDestination$ Exile | RememberFound$ True | SubAbility$ DBPlay | SpellDescription$ They exile cards from the top of their library until they exile a nonland card, then you may cast that card without paying its mana cost.
SVar:DBPlay:DB$ Play | Controller$ You | Defined$ Remembered | WithoutManaCost$ True | ValidSA$ Spell | Optional$ True | Amount$ All | SubAbility$ DBCleanup
SVar:DBDamage:DB$ Dig | RememberChanged$ True | DestinationZone$ Exile | Defined$ Remembered | DigNum$ 4 | ChangeNum$ All | SubAbility$ DamageOpponent | SpellDescription$ That player exiles the top four cards of their library and CARDNAME deals damage equal to the total mana value of those exiled cards to that player.
SVar:DamageOpponent:DB$ DealDamage | Defined$ Remembered | NumDmg$ X | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Remembered$SumCMC
Oracle:Each opponent faces a villainous choice — They exile cards from the top of their library until they exile a nonland card, then you may cast that card without paying its mana cost, or that player exiles the top four cards of their library and Ensnared by the Mara deals damage equal to the total mana value of those exiled cards to that player.
4 changes: 2 additions & 2 deletions forge-gui/res/cardsfolder/f/fatal_lore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ManaCost:2 B B
Types:Sorcery
A:SP$ Charm | Cost$ 2 B B | Chooser$ Opponent | Choices$ DrawThree,DestroyAndDraw
SVar:DrawThree:DB$ Draw | NumCards$ 3 | Defined$ You | SpellDescription$ You draw three cards.
SVar:DestroyAndDraw:DB$ Destroy | ValidTgts$ Creature.ChosenCtrl | TgtPrompt$ Select target creature | TargetMin$ 0 | TargetMax$ 2 | NoRegen$ True | SpellDescription$ You destroy up to two target creatures that opponent controls and that player draws up to three cards. Those creatures can't be regenerated. | SubAbility$ ChooserDraws
SVar:ChooserDraws:DB$ Draw | NumCards$ 3 | Defined$ ChosenPlayer | UpTo$ True
SVar:DestroyAndDraw:DB$ Destroy | ValidTgts$ Creature.ControlledBy ChoosingPlayer | TgtPrompt$ Select target creature | TargetMin$ 0 | TargetMax$ 2 | NoRegen$ True | SpellDescription$ You destroy up to two target creatures that opponent controls and that player draws up to three cards. Those creatures can't be regenerated. | SubAbility$ ChooserDraws
SVar:ChooserDraws:DB$ Draw | NumCards$ 3 | Defined$ ChoosingPlayer | UpTo$ True
AI:RemoveDeck:All
Oracle:An opponent chooses one —\n• You draw three cards.\n• You destroy up to two target creatures that player controls. They can't be regenerated. That player draws up to three cards.
14 changes: 14 additions & 0 deletions forge-gui/res/cardsfolder/g/genesis_of_the_daleks.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Name:Genesis of the Daleks
ManaCost:4 B B
Types:Enchantment Saga
K:Chapter:4:DBToken,DBToken,DBToken,DBVillainous
SVar:DBToken:DB$ Token | TokenAmount$ X | TokenScript$ b_3_3_a_dalek_menace | SpellDescription$ Create a 3/3 black Dalek artifact creature token with menace for each lore counter on CARDNAME.
SVar:DBVillainous:DB$ VillainousChoice | Choices$ DBDestroyDalek,DBDestroyNonDalek | ValidTgts$ Opponent | SpellDescription$ Target opponent faces a villainous choice — Destroy all Dalek creatures and each of your opponents loses life equal to the total power of Daleks that died this turn, or destroy all non-Dalek creatures.
SVar:DBDestroyDalek:DB$ DestroyAll | ValidCards$ Creature.Dalek | SubAbility$ DBLoseLife | SpellDescription$ Destroy all Dalek creatures and each of your opponents loses life equal to the total power of Daleks that died this turn.
SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ Y | Defined$ Opponent
SVar:DBDestroyNonDalek:DB$ DestroyAll | ValidCards$ Creature.nonDalek | SpellDescription$ Destroy all non-Dalek creatures.
SVar:X:Count$CardCounters.LORE
SVar:Y:Count$ThisTurnEntered_Graveyard_from_Battlefield_Dalek$CardPower
DeckHas:Ability$Token & Type$Artifact|Dalek
DeckHints:Type$Dalek
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after IV.)\nI, II, III — Create a 3/3 black Dalek artifact creature token with menace for each lore counter on Genesis of the Daleks.\nIV — Target opponent faces a villainous choice — Destroy all Dalek creatures and each of your opponents loses life equal to the total power of Daleks that died this turn, or destroy all non-Dalek creatures.
10 changes: 10 additions & 0 deletions forge-gui/res/cardsfolder/h/hunted_by_the_family.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Name:Hunted by The Family
ManaCost:5 U U
Types:Sorcery
A:SP$ ChooseCard | ValidTgts$ Creature.YouDontCtrl | TgtPrompt$ Select up to four target creatures you don't control | TargetMin$ 0 | TargetMax$ 4 | SubAbility$ DBRepeat | SpellDescription$ Choose up to four target creatures you don't control. For each of them, that creature's controller faces a villainous choice — That creature becomes a 1/1 white Human creature and loses all abilities, or you create a token that's a copy of it.
SVar:DBRepeat:DB$ RepeatEach | RepeatSubAbility$ DBChoice | DefinedCards$ Targeted
SVar:DBChoice:DB$ VillainousChoice | Defined$ RememberedController | Choices$ DBAnimate,DBCopy
SVar:DBAnimate:DB$ Animate | Defined$ Remembered | Power$ 1 | Toughness$ 1 | Types$ Creature,Human | RemoveCreatureTypes$ True | RemoveCardTypes$ True | RemoveAllAbilities$ True | IsCurse$ True | Colors$ White | OverwriteColors$ True | Duration$ Permanent | SpellDescription$ That creature becomes a 1/1 white Human creature and loses all abilities.
SVar:DBCopy:DB$ CopyPermanent | Defined$ Remembered | SpellDescription$ You create a token that's a copy of it.
DeckHas:Ability$Token & Type$Human
Oracle:Choose up to four target creatures you don't control. For each of them, that creature's controller faces a villainous choice — That creature becomes a 1/1 white Human creature and loses all abilities, or you create a token that's a copy of it.
15 changes: 15 additions & 0 deletions forge-gui/res/cardsfolder/m/midnight_crusader_shuttle.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Name:Midnight Crusader Shuttle
ManaCost:4
Types:Artifact Vehicle
PT:3/4
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigVillainousChoice | TriggerDescription$ Midnight Entity — Whenever CARDNAME attacks, defending player faces a villainous choice — That player sacrifices a creature, or you gain control of a creature of your choice that player controls until end of turn. If you gain control of a creature this way, tap it, and it's attacking that player.
SVar:TrigVillainousChoice:DB$ VillainousChoice | Defined$ TriggeredDefendingPlayer | Choices$ DBSacrifice,DBGainControl
SVar:DBSacrifice:DB$ Sacrifice | Amount$ 1 | SacValid$ Creature | Defined$ Remembered | SpellDescription$ That player sacrifices a creature.
SVar:DBGainControl:DB$ GainControl | Defined$ ChosenCard | Choices$ Creature.RememberedPlayerCtrl | ChoiceTitle$ Select a creature that player controls | NewController$ You | LoseControl$ EOT | RememberControlled$ True | SubAbility$ DBTap | SpellDescription$ You gain control of a creature of your choice that player controls until end of turn. If you gain control of a creature this way, tap it, and it's attacking that player.
SVar:DBTap:DB$ Tap | Defined$ Remembered | ConditionDefined$ Remembered | ConditionPresent$ Card.YouCtrl | SubAbility$ DBSetAttacking
SVar:DBSetAttacking:DB$ ChangeCombatants | Defined$ Remembered | ConditionDefined$ Remembered | ConditionPresent$ Card.YouCtrl | Attacking$ RememberedPlayer | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
K:Crew:2
SVar:HasAttackEffect:True
DeckHas:Ability$Sacrifice
Oracle:Midnight Entity — Whenever Midnight Crusader Shuttle attacks, defending player faces a villainous choice — That player sacrifices a creature, or you gain control of a creature of your choice that player controls until end of turn. If you gain control of a creature this way, tap it, and it's attacking that player.\nCrew 2
4 changes: 2 additions & 2 deletions forge-gui/res/cardsfolder/m/misfortune.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Types:Sorcery
A:SP$ Charm | Cost$ 1 B R G | Chooser$ Opponent | Choices$ Fortune,Misfortune
SVar:Fortune:DB$ PutCounterAll | ValidCards$ Creature.YouCtrl | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBGainLife | SpellDescription$ Put a +1/+1 counter on each creature you control. You gain 4 life. | SubAbility$ DBGainLife
SVar:DBGainLife:DB$ GainLife | LifeAmount$ 4
SVar:Misfortune:DB$ PutCounterAll | ValidCards$ Creature.ChosenCtrl | CounterType$ M1M1 | CounterNum$ 1 | SubAbility$ DBLoseLife | SpellDescription$ You put a -1/-1 counter on each creature that player controls and CARDNAME deals 4 damage to that player. | SubAbility$ DBDamage
SVar:DBDamage:DB$ DealDamage | Defined$ ChosenPlayer | NumDmg$ 4
SVar:Misfortune:DB$ PutCounterAll | ValidCards$ Creature.ControlledBy ChoosingPlayer | CounterType$ M1M1 | CounterNum$ 1 | SubAbility$ DBLoseLife | SpellDescription$ You put a -1/-1 counter on each creature that player controls and CARDNAME deals 4 damage to that player. | SubAbility$ DBDamage
SVar:DBDamage:DB$ DealDamage | Defined$ ChoosingPlayer | NumDmg$ 4
SVar:ChooserDraws:DB$ Draw | NumCards$ 3 | Defined$ ChosenPlayer
Oracle:An opponent chooses one —\n• You put a +1/+1 counter on each creature you control and gain 4 life.\n• You put a -1/-1 counter on each creature that player controls and Misfortune deals 4 damage to that player.
Loading

0 comments on commit 81de9a6

Please sign in to comment.