From 4074a301f740be46475502bb9e6013d3865f65d5 Mon Sep 17 00:00:00 2001 From: Simisays <67333662+Simisays@users.noreply.github.com> Date: Sun, 23 Jun 2024 17:47:52 +0200 Subject: [PATCH 1/6] map fixes (#5460) --- .../res/adventure/common/maps/map/cave/cave_kobold_floor2.tmx | 2 +- .../common/maps/map/fort/fort_colorless_7_multilevel3.tmx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/forge-gui/res/adventure/common/maps/map/cave/cave_kobold_floor2.tmx b/forge-gui/res/adventure/common/maps/map/cave/cave_kobold_floor2.tmx index 99f3fa81f44..150da89a122 100644 --- a/forge-gui/res/adventure/common/maps/map/cave/cave_kobold_floor2.tmx +++ b/forge-gui/res/adventure/common/maps/map/cave/cave_kobold_floor2.tmx @@ -32,7 +32,7 @@ - + diff --git a/forge-gui/res/adventure/common/maps/map/fort/fort_colorless_7_multilevel3.tmx b/forge-gui/res/adventure/common/maps/map/fort/fort_colorless_7_multilevel3.tmx index 4af1cd7edf7..06685db5322 100644 --- a/forge-gui/res/adventure/common/maps/map/fort/fort_colorless_7_multilevel3.tmx +++ b/forge-gui/res/adventure/common/maps/map/fort/fort_colorless_7_multilevel3.tmx @@ -36,6 +36,7 @@ + From 5f74aec97d9748524207ab3f396e531ceb8caadc Mon Sep 17 00:00:00 2001 From: tool4ever Date: Sun, 23 Jun 2024 22:36:58 +0000 Subject: [PATCH 2/6] Update vault_11_voters_dilemma.txt --- forge-gui/res/cardsfolder/v/vault_11_voters_dilemma.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-gui/res/cardsfolder/v/vault_11_voters_dilemma.txt b/forge-gui/res/cardsfolder/v/vault_11_voters_dilemma.txt index 054b86810e8..116733bb8a5 100644 --- a/forge-gui/res/cardsfolder/v/vault_11_voters_dilemma.txt +++ b/forge-gui/res/cardsfolder/v/vault_11_voters_dilemma.txt @@ -4,7 +4,7 @@ Types:Enchantment Saga K:Chapter:3:DBToken,DBVote,DBVote SVar:DBToken:DB$ Token | TokenAmount$ OneEach | TokenScript$ w_1_1_human_soldier SVar:OneEach:PlayerCountOpponents$Amount -SVar:DBVote:DB$ Vote | Defined$ Player | Secretly$ True | VoteCard$ Creature | VoteMessage$ for a creature | UpTo$ True | VoteSubAbility$ DBDestroyAll | SubAbility$ DBBranch | SpellDescription$ Each player secretly votes for up to one creature, then those votes are revealed. If no creature got votes, each player draws a card. Otherwise, destroy each creature with the most votes or tied for most votes. +SVar:DBVote:DB$ Vote | Defined$ Player | Secretly$ True | VoteCard$ Creature | VoteMessage$ for a creature | UpTo$ True | VoteSubAbility$ DBDestroyAll | SpellDescription$ Each player secretly votes for up to one creature, then those votes are revealed. If no creature got votes, each player draws a card. Otherwise, destroy each creature with the most votes or tied for most votes. SVar:DBDestroyAll:DB$ DestroyAll | ValidCards$ Creature.IsRemembered | SubAbility$ DBDraw SVar:DBDraw:DB$ Draw | Defined$ Player | NumCards$ 1 | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ0 SVar:X:Remembered$Amount From 72af32c9821e993d639ff29b6d1160bfff1eca13 Mon Sep 17 00:00:00 2001 From: tool4ever Date: Mon, 24 Jun 2024 06:53:19 +0000 Subject: [PATCH 3/6] Update desmond_miles.txt --- forge-gui/res/cardsfolder/upcoming/desmond_miles.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/forge-gui/res/cardsfolder/upcoming/desmond_miles.txt b/forge-gui/res/cardsfolder/upcoming/desmond_miles.txt index 87605dd7ee9..1baec79ffcd 100644 --- a/forge-gui/res/cardsfolder/upcoming/desmond_miles.txt +++ b/forge-gui/res/cardsfolder/upcoming/desmond_miles.txt @@ -1,4 +1,5 @@ Name:Desmond Miles +ManaCost:1 B Types:Legendary Creature Human Assassin PT:1/3 K:Menace From fe7043dd0d043ed34a3e4ebe466ab101471ac0c2 Mon Sep 17 00:00:00 2001 From: tool4ever Date: Mon, 24 Jun 2024 06:53:42 +0000 Subject: [PATCH 4/6] Update evie_frye.txt --- forge-gui/res/cardsfolder/upcoming/evie_frye.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/forge-gui/res/cardsfolder/upcoming/evie_frye.txt b/forge-gui/res/cardsfolder/upcoming/evie_frye.txt index 3d638225d41..638c8991d11 100644 --- a/forge-gui/res/cardsfolder/upcoming/evie_frye.txt +++ b/forge-gui/res/cardsfolder/upcoming/evie_frye.txt @@ -1,4 +1,5 @@ Name:Evie Frye +ManaCost:1 B Types:Legendary Creature Human Assassin PT:2/1 K:Partner:Jacob Frye From d5ab4be4512087fc98aa291ee462580fa7c6ab5e Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 24 Jun 2024 13:48:20 +0200 Subject: [PATCH 5/6] Invasion Plans using Timestamp instead (#5458) * Invasion Plans using ReplacementEffect instead * StaticAbilityContinuous: use DeclaresAttackers and DeclaresBlockers with ts * update scripts * Update master_warcraft.txt * Player: update DeclaresAttacker and DeclaresBlocker with getDefinedPlayers --------- Co-authored-by: tool4ever --- .../src/main/java/forge/ai/SpellApiToAi.java | 1 - .../java/forge/game/GlobalRuleChange.java | 42 ------------ .../main/java/forge/game/StaticEffect.java | 3 + .../main/java/forge/game/StaticEffects.java | 13 ---- .../main/java/forge/game/ability/ApiType.java | 1 - .../effects/DeclareCombatantsEffect.java | 65 ------------------- .../ability/effects/RestartGameEffect.java | 2 - .../java/forge/game/phase/PhaseHandler.java | 22 ++----- .../main/java/forge/game/player/Player.java | 33 +++++++++- .../forge/game/player/PlayerProperty.java | 4 ++ .../game/staticability/StaticAbility.java | 3 +- .../StaticAbilityContinuous.java | 17 +++-- .../res/cardsfolder/b/berserkers_frenzy.txt | 3 +- .../res/cardsfolder/b/brutal_hordechief.txt | 4 +- .../res/cardsfolder/i/invasion_plans.txt | 2 +- .../res/cardsfolder/m/master_warcraft.txt | 3 +- forge-gui/res/cardsfolder/m/melee.txt | 4 +- .../cardsfolder/o/odric_master_tactician.txt | 3 +- 18 files changed, 66 insertions(+), 159 deletions(-) delete mode 100644 forge-game/src/main/java/forge/game/GlobalRuleChange.java delete mode 100644 forge-game/src/main/java/forge/game/ability/effects/DeclareCombatantsEffect.java diff --git a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java index accd75afab7..28f5cc117e2 100644 --- a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java @@ -69,7 +69,6 @@ public enum SpellApiToAi { .put(ApiType.DayTime, DayTimeAi.class) .put(ApiType.DealDamage, DamageDealAi.class) .put(ApiType.Debuff, DebuffAi.class) - .put(ApiType.DeclareCombatants, CannotPlayAi.class) .put(ApiType.DelayedTrigger, DelayedTriggerAi.class) .put(ApiType.Destroy, DestroyAi.class) .put(ApiType.DestroyAll, DestroyAllAi.class) diff --git a/forge-game/src/main/java/forge/game/GlobalRuleChange.java b/forge-game/src/main/java/forge/game/GlobalRuleChange.java deleted file mode 100644 index aa68c75f978..00000000000 --- a/forge-game/src/main/java/forge/game/GlobalRuleChange.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Forge: Play Magic: the Gathering. - * Copyright (C) 2011 Forge Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package forge.game; - -/** - * The Enum GlobalRuleChange. - */ -public enum GlobalRuleChange { - - attackerChoosesBlockers ("The attacking player chooses how each creature blocks each combat."); - - private final String ruleText; - - GlobalRuleChange(String text) { - ruleText = text; - } - - public static GlobalRuleChange fromString(String text) { - for (final GlobalRuleChange v : GlobalRuleChange.values()) { - if (v.ruleText.compareToIgnoreCase(text) == 0) { - return v; - } - } - - throw new RuntimeException("Element " + text + " not found in GlobalRuleChange enum"); - } -} diff --git a/forge-game/src/main/java/forge/game/StaticEffect.java b/forge-game/src/main/java/forge/game/StaticEffect.java index 831fda76d9d..d5890e5ff6c 100644 --- a/forge-game/src/main/java/forge/game/StaticEffect.java +++ b/forge-game/src/main/java/forge/game/StaticEffect.java @@ -198,6 +198,9 @@ public class StaticEffect { p.removeAdditionalVote(getTimestamp()); p.removeAdditionalOptionalVote(getTimestamp()); p.removeAdditionalVillainousChoices(getTimestamp()); + + p.removeDeclaresAttackers(getTimestamp()); + p.removeDeclaresBlockers(getTimestamp()); } // modify the affected card diff --git a/forge-game/src/main/java/forge/game/StaticEffects.java b/forge-game/src/main/java/forge/game/StaticEffects.java index af677db1a3f..0b56db9cfbe 100644 --- a/forge-game/src/main/java/forge/game/StaticEffects.java +++ b/forge-game/src/main/java/forge/game/StaticEffects.java @@ -17,7 +17,6 @@ */ package forge.game; -import java.util.EnumSet; import java.util.Map; import java.util.Set; @@ -39,12 +38,8 @@ public class StaticEffects { // **************** StaticAbility system ************************** private final Map staticEffects = Maps.newHashMap(); - //Global rule changes - private final Set ruleChanges = EnumSet.noneOf(GlobalRuleChange.class); public final void clearStaticEffects(final Set affectedCards) { - ruleChanges.clear(); - // remove all static effects for (final StaticEffect se : staticEffects.values()) { Iterables.addAll(affectedCards, se.remove()); @@ -52,14 +47,6 @@ public class StaticEffects { this.staticEffects.clear(); } - public void setGlobalRuleChange(final GlobalRuleChange change) { - this.ruleChanges.add(change); - } - - public boolean getGlobalRuleChange(final GlobalRuleChange change) { - return this.ruleChanges.contains(change); - } - /** * Add a static effect to the list of static effects. * diff --git a/forge-game/src/main/java/forge/game/ability/ApiType.java b/forge-game/src/main/java/forge/game/ability/ApiType.java index 6fe2ce456e5..158385bc8cb 100644 --- a/forge-game/src/main/java/forge/game/ability/ApiType.java +++ b/forge-game/src/main/java/forge/game/ability/ApiType.java @@ -66,7 +66,6 @@ public enum ApiType { DealDamage (DamageDealEffect.class), DayTime (DayTimeEffect.class), Debuff (DebuffEffect.class), - DeclareCombatants (DeclareCombatantsEffect.class), DelayedTrigger (DelayedTriggerEffect.class), Destroy (DestroyEffect.class), DestroyAll (DestroyAllEffect.class), diff --git a/forge-game/src/main/java/forge/game/ability/effects/DeclareCombatantsEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DeclareCombatantsEffect.java deleted file mode 100644 index f7d5b928985..00000000000 --- a/forge-game/src/main/java/forge/game/ability/effects/DeclareCombatantsEffect.java +++ /dev/null @@ -1,65 +0,0 @@ -package forge.game.ability.effects; - -import java.util.List; - -import forge.GameCommand; -import forge.game.ability.SpellAbilityEffect; -import forge.game.phase.PhaseHandler; -import forge.game.player.Player; -import forge.game.spellability.SpellAbility; -import forge.util.Lang; -import forge.util.TextUtil; - -public class DeclareCombatantsEffect extends SpellAbilityEffect { - - @Override - protected String getStackDescription(SpellAbility sa) { - List tgtPlayers = getDefinedPlayersOrTargeted(sa); - boolean attackers = sa.hasParam("DeclareAttackers"); - boolean blockers = sa.hasParam("DeclareBlockers"); - String what = Lang.joinHomogenous( - attackers - ? "which creatures attack" - : null, - blockers - ? "which creatures block this turn and how those creatures block" - : null - ); - String duration = "EndOfTurn".equals(sa.getParam("Until")) ? "turn" : "combat"; - return TextUtil.concatWithSpace(Lang.joinHomogenous(tgtPlayers),Lang.joinVerb(tgtPlayers, "choose"),what,"this",TextUtil.addSuffix(duration,".")); - } - - @Override - public void resolve(SpellAbility sa) { - List tgtPlayers = getDefinedPlayersOrTargeted(sa); - - final boolean attackers = sa.hasParam("DeclareAttackers"); - final boolean blockers = sa.hasParam("DeclareBlockers"); - - String until = sa.getParam("Until"); - boolean untilEoT = "EndOfTurn".equals(until); - - for (Player p : tgtPlayers) { // Obviously the last player will be applied - final PhaseHandler ph = p.getGame().getPhaseHandler(); - if (attackers) ph.setPlayerDeclaresAttackers(p); - if (blockers) ph.setPlayerDeclaresBlockers(p); - - GameCommand removeOverrides = new GameCommand() { - private static final long serialVersionUID = -8064627517852651016L; - - @Override - public void run() { - if (attackers) ph.setPlayerDeclaresAttackers(null); - if (blockers) ph.setPlayerDeclaresBlockers(null); - } - }; - - if (untilEoT) - p.getGame().getEndOfTurn().addUntil(removeOverrides); - else - p.getGame().getEndOfCombat().addUntil(removeOverrides); - } - - } - -} diff --git a/forge-game/src/main/java/forge/game/ability/effects/RestartGameEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RestartGameEffect.java index 4d6efae1e97..67bfc46627a 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RestartGameEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RestartGameEffect.java @@ -44,8 +44,6 @@ public class RestartGameEffect extends SpellAbilityEffect { trigHandler.suppressMode(TriggerType.Shuffled); game.getPhaseHandler().restart(); - game.getPhaseHandler().setPlayerDeclaresAttackers(null); - game.getPhaseHandler().setPlayerDeclaresBlockers(null); game.getUntap().clearCommands(); game.getUpkeep().clearCommands(); game.getEndOfCombat().clearCommands(); diff --git a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java index f0c773302ca..556fc3c2aba 100644 --- a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java +++ b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java @@ -45,6 +45,8 @@ import forge.util.CollectionSuppliers; import forge.util.TextUtil; import forge.util.maps.HashMapOfLists; import forge.util.maps.MapOfLists; + +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.time.StopWatch; import java.util.*; @@ -84,9 +86,6 @@ public class PhaseHandler implements java.io.Serializable { private transient Combat combat = null; private boolean bRepeatCleanup = false; - private transient Player playerDeclaresBlockers = null; - private transient Player playerDeclaresAttackers = null; - /** The need to next phase. */ private boolean givePriorityToPlayer = false; @@ -523,9 +522,7 @@ public class PhaseHandler implements java.io.Serializable { } private void declareAttackersTurnBasedAction() { - final Player whoDeclares = playerDeclaresAttackers == null || playerDeclaresAttackers.hasLost() - ? playerTurn - : playerDeclaresAttackers; + final Player whoDeclares = ObjectUtils.firstNonNull(playerTurn.getDeclaresAttackers(), playerTurn); if (CombatUtil.canAttack(playerTurn)) { boolean success = false; @@ -653,10 +650,7 @@ public class PhaseHandler implements java.io.Serializable { do { p = game.getNextPlayerAfter(p); // Apply Odric's effect here - Player whoDeclaresBlockers = playerDeclaresBlockers == null || playerDeclaresBlockers.hasLost() ? p : playerDeclaresBlockers; - if (game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.attackerChoosesBlockers)) { - whoDeclaresBlockers = combat.getAttackingPlayer(); - } + Player whoDeclaresBlockers = ObjectUtils.firstNonNull(p.getDeclaresBlockers(), p); if (combat.isPlayerAttacked(p)) { if (CombatUtil.canBlock(p, combat)) { // Replacement effects (for Camouflage) @@ -1235,14 +1229,6 @@ public class PhaseHandler implements java.io.Serializable { givePriorityToPlayer = true; } - public final void setPlayerDeclaresAttackers(Player player) { - playerDeclaresAttackers = player; - } - - public final void setPlayerDeclaresBlockers(Player player) { - playerDeclaresBlockers = player; - } - public void endCombat() { game.getEndOfCombat().executeUntil(); game.getEndOfCombat().executeUntilEndOfPhase(playerTurn); diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 2e5f694eb72..192c85223b1 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -194,6 +194,9 @@ public class Player extends GameEntity implements Comparable { private SortedSet controlVotes = Sets.newTreeSet(); private Map additionalVillainousChoices = Maps.newHashMap(); + private NavigableMap declaresAttackers = Maps.newTreeMap(); + private NavigableMap declaresBlockers = Maps.newTreeMap(); + private final AchievementTracker achievementTracker = new AchievementTracker(); private final PlayerView view; @@ -904,7 +907,7 @@ public class Player extends GameEntity implements Comparable { setCounters(counterName, newValue, null, true); getGame().addCounterRemovedThisTurn(counterName, this, delta); - + /* TODO Run triggers when something cares int curCounters = oldValue; for (int i = 0; i < delta && curCounters != 0; i++) { @@ -2301,7 +2304,7 @@ public class Player extends GameEntity implements Comparable { public final void addSpellCastSinceBegOfYourLastTurn(List spells) { spellsCastSinceBeginningOfLastTurn.addAll(spells); } - + public final int getSpellsCastThisTurn() { return spellsCastThisTurn; } @@ -3814,4 +3817,30 @@ public class Player extends GameEntity implements Comparable { public void setCommitedCrimeThisTurn(int v) { committedCrimeThisTurn = v; } + + public void addDeclaresAttackers(long ts, Player p) { + this.declaresAttackers.put(ts, p); + } + + public void removeDeclaresAttackers(long ts) { + this.declaresAttackers.remove(ts); + } + + public Player getDeclaresAttackers() { + Map.Entry e = declaresAttackers.lastEntry(); + return e == null ? null : e.getValue(); + } + + public void addDeclaresBlockers(long ts, Player p) { + this.declaresBlockers.put(ts, p); + } + + public void removeDeclaresBlockers(long ts) { + this.declaresBlockers.remove(ts); + } + + public Player getDeclaresBlockers() { + Map.Entry e = declaresBlockers.lastEntry(); + return e == null ? null : e.getValue(); + } } diff --git a/forge-game/src/main/java/forge/game/player/PlayerProperty.java b/forge-game/src/main/java/forge/game/player/PlayerProperty.java index 0cb78e63007..8560ff530be 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerProperty.java +++ b/forge-game/src/main/java/forge/game/player/PlayerProperty.java @@ -175,6 +175,10 @@ public class PlayerProperty { if (!source.getDamageHistory().hasAttackedThisTurn(player)) { return false; } + } else if (property.equals("Attacking")) { + if (game.getCombat() == null || !player.equals(game.getCombat().getAttackingPlayer())) { + return false; + } } else if (property.equals("Defending")) { if (game.getCombat() == null || !game.getCombat().getAttackersAndDefenders().values().contains(player)) { return false; diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java index 2eb046c689d..f3abfe6607b 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java @@ -165,7 +165,8 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone if (hasParam("AddHiddenKeyword") || hasParam("MayPlay") || hasParam("IgnoreEffectCost") || hasParam("Goad") || hasParam("CanBlockAny") || hasParam("CanBlockAmount") - || hasParam("AdjustLandPlays") || hasParam("ControlVote") || hasParam("AdditionalVote") || hasParam("AdditionalOptionalVote")) { + || hasParam("AdjustLandPlays") || hasParam("ControlVote") || hasParam("AdditionalVote") || hasParam("AdditionalOptionalVote") + || hasParam("DeclaresAttackers") || hasParam("DeclaresBlockers")) { layers.add(StaticAbilityLayer.RULES); } diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java index a6fbdf79a1e..ed25ebd56f0 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java @@ -26,7 +26,6 @@ import com.google.common.collect.Maps; import forge.GameCommand; import forge.card.*; import forge.game.Game; -import forge.game.GlobalRuleChange; import forge.game.StaticEffect; import forge.game.StaticEffects; import forge.game.ability.AbilityUtils; @@ -142,11 +141,6 @@ public final class StaticAbilityContinuous { boolean mayPlayGrantZonePermissions = true; Integer mayPlayLimit = null; - //Global rules changes - if (layer == StaticAbilityLayer.RULES && params.containsKey("GlobalRule")) { - effects.setGlobalRuleChange(GlobalRuleChange.fromString(params.get("GlobalRule"))); - } - if (layer == StaticAbilityLayer.SETPT || layer == StaticAbilityLayer.CHARACTERISTIC) { if (params.containsKey("SetPower")) { setP = params.get("SetPower"); @@ -599,6 +593,17 @@ public final class StaticAbilityContinuous { int add = AbilityUtils.calculateAmount(hostCard, mhs, stAb); p.addAdditionalVillainousChoices(se.getTimestamp(), add); } + + if (params.containsKey("DeclaresAttackers")) { + PlayerCollection players = AbilityUtils.getDefinedPlayers(hostCard, params.get("DeclaresAttackers"), stAb); + if (!players.isEmpty()) + p.addDeclaresAttackers(se.getTimestamp(), players.getFirst()); + } + if (params.containsKey("DeclaresBlockers")) { + PlayerCollection players = AbilityUtils.getDefinedPlayers(hostCard, params.get("DeclaresBlockers"), stAb); + if (!players.isEmpty()) + p.addDeclaresBlockers(se.getTimestamp(), players.getFirst()); + } } } diff --git a/forge-gui/res/cardsfolder/b/berserkers_frenzy.txt b/forge-gui/res/cardsfolder/b/berserkers_frenzy.txt index 3ccc98b64d4..975904711ae 100644 --- a/forge-gui/res/cardsfolder/b/berserkers_frenzy.txt +++ b/forge-gui/res/cardsfolder/b/berserkers_frenzy.txt @@ -6,5 +6,6 @@ SVar:MustBlock:DB$ ChooseCard | Choices$ Creature | Amount$ X | MinAmount$ 0 | C SVar:DBEffect:DB$ Effect | StaticAbilities$ StaticBlock SVar:StaticBlock:Mode$ MustBlock | ValidCreature$ Card.ChosenCardStrict | Description$ The chosen creatures block this turn if able. SVar:X:Count$Valid Creature -SVar:ChooseBlock:DB$ DeclareCombatants | DeclareBlockers$ True | Until$ EndOfTurn | SpellDescription$ 15—20 VERT You choose which creatures block this turn and how those creatures block. +SVar:ChooseBlock:DB$ Effect | StaticAbilities$ DeclareCombatants | SpellDescription$ 15—20 VERT You choose which creatures block this turn and how those creatures block. +SVar:DeclareCombatants:Mode$ Continuous | Affected$ Player | DeclaresBlockers$ You | Description$ You choose which creatures block this combat and how those creatures block. Oracle:Cast this spell only before combat or during combat before blockers are declared.\nRoll two d20 and ignore the lower roll.\n1—14 | Choose any number of creatures. They block this turn if able.\n15—20 | You choose which creatures block this turn and how those creatures block. diff --git a/forge-gui/res/cardsfolder/b/brutal_hordechief.txt b/forge-gui/res/cardsfolder/b/brutal_hordechief.txt index c664e48177b..dda352c13a6 100644 --- a/forge-gui/res/cardsfolder/b/brutal_hordechief.txt +++ b/forge-gui/res/cardsfolder/b/brutal_hordechief.txt @@ -5,9 +5,9 @@ PT:3/3 T:Mode$ Attacks | ValidCard$ Creature.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigLoseLife | TriggerDescription$ Whenever a creature you control attacks, defending player loses 1 life and you gain 1 life. SVar:TrigLoseLife:DB$ LoseLife | Defined$ TriggeredDefendingPlayer | LifeAmount$ 1 | SubAbility$ DBGainLife SVar:DBGainLife:DB$ GainLife | LifeAmount$ 1 -A:AB$ Effect | Cost$ 3 RW RW | StaticAbilities$ STBlock | SubAbility$ DBDeclareCombatants | SpellDescription$ Creatures your opponents control block this turn if able, and you choose how those creatures block. +A:AB$ Effect | Cost$ 3 RW RW | StaticAbilities$ STBlock,DeclareCombatants | SpellDescription$ Creatures your opponents control block this turn if able, and you choose how those creatures block. SVar:STBlock:Mode$ MustBlock | ValidCreature$ Creature.OppCtrl | Description$ Creatures your opponents control block this turn if able, and you choose how those creatures block. -SVar:DBDeclareCombatants:DB$ DeclareCombatants | DeclareBlockers$ True | Until$ EndOfTurn +SVar:DeclareCombatants:Mode$ Continuous | Affected$ Player.Opponent | DeclaresBlockers$ You | Description$ You choose how those creatures block. SVar:HasAttackEffect:TRUE DeckHas:Ability$LifeGain Oracle:Whenever a creature you control attacks, defending player loses 1 life and you gain 1 life.\n{3}{R/W}{R/W}: Creatures your opponents control block this turn if able, and you choose how those creatures block. diff --git a/forge-gui/res/cardsfolder/i/invasion_plans.txt b/forge-gui/res/cardsfolder/i/invasion_plans.txt index 31498af9d04..ebcb38b8a38 100644 --- a/forge-gui/res/cardsfolder/i/invasion_plans.txt +++ b/forge-gui/res/cardsfolder/i/invasion_plans.txt @@ -2,7 +2,7 @@ Name:Invasion Plans ManaCost:2 R Types:Enchantment S:Mode$ MustBlock | ValidCreature$ Creature | Description$ All creatures block each combat if able. -S:Mode$ Continuous | GlobalRule$ The attacking player chooses how each creature blocks each combat. | Description$ The attacking player chooses how each creature blocks each combat. +S:Mode$ Continuous | Affected$ Player | DeclaresBlockers$ AttackingPlayer | Description$ The attacking player chooses how each creature blocks each combat. SVar:NonStackingEffect:True AI:RemoveDeck:Random Oracle:All creatures block each combat if able.\nThe attacking player chooses how each creature blocks each combat. diff --git a/forge-gui/res/cardsfolder/m/master_warcraft.txt b/forge-gui/res/cardsfolder/m/master_warcraft.txt index d93314b896d..ce81131b954 100644 --- a/forge-gui/res/cardsfolder/m/master_warcraft.txt +++ b/forge-gui/res/cardsfolder/m/master_warcraft.txt @@ -1,6 +1,7 @@ Name:Master Warcraft ManaCost:2 RW RW Types:Instant -A:SP$ DeclareCombatants | DeclareAttackers$ True | DeclareBlockers$ True | ActivationPhases$ Upkeep->BeginCombat | ActivationFirstCombat$ True | Until$ EndOfTurn | SpellDescription$ Cast this spell only before attackers are declared. You choose which creatures attack this turn. You choose which creatures block this turn and how those creatures block. +A:SP$ Effect | StaticAbilities$ DeclareCombatants | ActivationPhases$ Upkeep->BeginCombat | ActivationFirstCombat$ True | SpellDescription$ Cast this spell only before attackers are declared. You choose which creatures attack this turn. You choose which creatures block this turn and how those creatures block. +SVar:DeclareCombatants:Mode$ Continuous | Affected$ Player | DeclaresAttackers$ You | DeclaresBlockers$ You | Description$ You choose which creatures attack this turn. You choose which creatures block this turn and how those creatures block. AI:RemoveDeck:All Oracle:Cast this spell only before attackers are declared.\nYou choose which creatures attack this turn.\nYou choose which creatures block this turn and how those creatures block. diff --git a/forge-gui/res/cardsfolder/m/melee.txt b/forge-gui/res/cardsfolder/m/melee.txt index ea705596a08..e7a5d080fc0 100644 --- a/forge-gui/res/cardsfolder/m/melee.txt +++ b/forge-gui/res/cardsfolder/m/melee.txt @@ -1,8 +1,8 @@ Name:Melee ManaCost:4 R Types:Instant -A:SP$ DeclareCombatants | DeclareBlockers$ True | PlayerTurn$ True | ActivationPhases$ BeginCombat->Declare Attackers | SubAbility$ DBEffect | SpellDescription$ Cast this spell only during your turn and only during combat before blockers are declared. You choose which creatures block this combat and how those creatures block. Whenever a creature attacks and isn't blocked this combat, untap it and remove it from combat. -SVar:DBEffect:DB$ Effect | Triggers$ TrigAttack | Duration$ UntilEndOfCombat +A:SP$ Effect | StaticAbilities$ DeclareCombatants | Triggers$ TrigAttack | Duration$ UntilEndOfCombat | PlayerTurn$ True | ActivationPhases$ BeginCombat->Declare Attackers | SpellDescription$ Cast this spell only during your turn and only during combat before blockers are declared. You choose which creatures block this combat and how those creatures block. Whenever a creature attacks and isn't blocked this combat, untap it and remove it from combat. +SVar:DeclareCombatants:Mode$ Continuous | Affected$ Player | DeclaresBlockers$ You | Description$ You choose which creatures block this combat and how those creatures block. SVar:TrigAttack:Mode$ AttackerUnblocked | ValidCard$ Creature | Execute$ TrigUntap | TriggerZones$ Command | TriggerDescription$ Whenever a creature attacks and isn't blocked this combat, untap it and remove it from combat. SVar:TrigUntap:DB$ Untap | Defined$ TriggeredAttackerLKICopy | SubAbility$ RemCombat SVar:RemCombat:DB$ RemoveFromCombat | Defined$ TriggeredAttackerLKICopy diff --git a/forge-gui/res/cardsfolder/o/odric_master_tactician.txt b/forge-gui/res/cardsfolder/o/odric_master_tactician.txt index 243b4901964..fe4c04ee2d0 100644 --- a/forge-gui/res/cardsfolder/o/odric_master_tactician.txt +++ b/forge-gui/res/cardsfolder/o/odric_master_tactician.txt @@ -4,6 +4,7 @@ Types:Legendary Creature Human Soldier PT:3/4 K:First Strike T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | IsPresent$ Creature.attacking+Other | PresentCompare$ GE3 | NoResolvingCheck$ True | Execute$ TrigOdricEffect | TriggerDescription$ Whenever CARDNAME and at least three other creatures attack, you choose which creatures block this combat and how those creatures block. -SVar:TrigOdricEffect:DB$ DeclareCombatants | DeclareBlockers$ True +SVar:TrigOdricEffect:DB$ Effect | StaticAbilities$ DeclareCombatants | Duration$ UntilEndOfCombat +SVar:DeclareCombatants:Mode$ Continuous | Affected$ Player | DeclaresBlockers$ You | Description$ You choose which creatures block this combat and how those creatures block. AI:RemoveDeck:All Oracle:First strike (This creature deals combat damage before creatures without first strike.)\nWhenever Odric, Master Tactician and at least three other creatures attack, you choose which creatures block this combat and how those creatures block. From 3ef9aa048a9486ee984024ab2adfb4568a489a50 Mon Sep 17 00:00:00 2001 From: Chris H Date: Sun, 23 Jun 2024 22:06:58 -0400 Subject: [PATCH 6/6] MH3 booster definition --- forge-gui/res/editions/Modern Horizons 3.txt | 62 ++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/forge-gui/res/editions/Modern Horizons 3.txt b/forge-gui/res/editions/Modern Horizons 3.txt index 21c65a7fbee..c73f17dd27d 100644 --- a/forge-gui/res/editions/Modern Horizons 3.txt +++ b/forge-gui/res/editions/Modern Horizons 3.txt @@ -3,6 +3,12 @@ Code=MH3 Date=2024-06-07 Name=Modern Horizons 3 Type=Draft +Booster=6 Common, 3 Uncommon, 1 RareMythic, 1 fromSheet("MH3 new to modern"), 1 Land, 1 Any, 1 Any+ +# This isn't the right ratios yet. But it's a start +ChanceReplaceCommonWith=.0156F fromsheet("MH3 special guests") +BoosterBox=36 +BoosterCovers=3 +ChaosDraftThemes=MASTERS_SET ScryfallCode=MH3 [cards] @@ -536,6 +542,62 @@ ScryfallCode=MH3 495 R Powerbalance @Liiga Smilshkalne 496 R Flusterstorm @Andrew Mar +[new to modern] +1 Angel of the Ruins|MH3 +1 Decree of Justice|MH3 +1 Distinguished Conjurer|MH3 +1 Orim's Chant|MH3 +1 Recruiter of the Guard|MH3 +1 Sevinne's Reclamation|MH3 +1 Deep Analysis|MH3 +1 Estrid's Invocation|MH3 +1 Kappa Cannoneer|MH3 +1 Reef Worm|MH3 +1 Shrieking Drake|MH3 +1 Buried Alive|MH3 +1 K'rrik, Son of Yawgmoth|MH3 +1 Nadier's Nightblade|MH3 +1 Ophiomancer|MH3 +1 Toxic Deluge|MH3 +1 Victimize|MH3 +1 Cursed Mirror|MH3 +1 Fledgling Dragon|MH3 +1 Laelia, the Blade Reforged|MH3 +1 Meltdown|MH3 +1 Meteoric Mace|MH3 +1 Annoyed Altisaur|MH3 +1 Branching Evolution|MH3 +1 Priest of Titania|MH3 +1 Sylvan Safekeeper|MH3 +1 Wirewood Symbiote|MH3 +1 Breya, Etherium Shaper|MH3 +1 Kaalia of the Vast|MH3 +1 Emerald Medallion|MH3 +1 Jet Medallion|MH3 +1 Junk Diver|MH3 +1 Pearl Medallion|MH3 +1 Ruby Medallion|MH3 +1 Sapphire Medallion|MH3 +1 Urza's Incubator|MH3 +1 Worn Powerstone|MH3 +1 Barbarian Ring|MH3 +1 Cephalid Coliseum|MH3 +1 Deserted Temple|MH3 +1 Nesting Grounds|MH3 +1 Phyrexian Tower|MH3 + +[special guests] +1 Thought-Knot Seer|SPG +1 Prismatic Ending|SPG +1 Dismember|SPG +1 Persist|SPG +1 Expressive Iteration|SPG +1 Solitude|SPG +1 Subtlety|SPG +1 Grief|SPG +1 Fury|SPG +1 Endurance|SPG + [tokens] b_0_0_phyrexian_germ b_0_0_zombie_army