diff --git a/.gitignore b/.gitignore index fa8fced8097..1428f445c06 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,7 @@ Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/target Mage.Server.Plugins/Mage.Game.FreeformCommanderDuel/target/ Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/target/ Mage.Server.Plugins/Mage.Game.FreeformUnlimitedCommander/target/ +Mage.Server.Plugins/Mage.Game.CustomPillarOfTheParunsDuel/target/ Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/target Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/target Mage.Server.Plugins/Mage.Player.AI.DraftBot/target diff --git a/Mage.Server.Plugins/Mage.Game.CustomPillarOfTheParunsDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.CustomPillarOfTheParunsDuel/pom.xml new file mode 100644 index 00000000000..7456f5aa11e --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.CustomPillarOfTheParunsDuel/pom.xml @@ -0,0 +1,55 @@ + + + + 4.0.0 + + + org.mage + mage-server-plugins + 1.4.50 + + + mage-game-custompillaroftheparunsduel + jar + Mage Game Custom Pillar of the Paruns Two Player Duel + + + + ${project.groupId} + mage + ${project.version} + + + ${project.groupId} + mage-sets + ${project.version} + + + + + src + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + + maven-resources-plugin + + UTF-8 + + + + + + mage-game-custompillaroftheparunsduel + + + + + diff --git a/Mage.Server.Plugins/Mage.Game.CustomPillarOfTheParunsDuel/src/mage/game/CustomPillarOfTheParunsDuel.java b/Mage.Server.Plugins/Mage.Game.CustomPillarOfTheParunsDuel/src/mage/game/CustomPillarOfTheParunsDuel.java new file mode 100644 index 00000000000..d01c231e010 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.CustomPillarOfTheParunsDuel/src/mage/game/CustomPillarOfTheParunsDuel.java @@ -0,0 +1,150 @@ +package mage.game; + +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ConjureCardEffect; +import mage.constants.*; +import mage.game.events.GameEvent; +import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; +import mage.game.turn.TurnMod; +import mage.players.Player; + +import java.util.UUID; + +/** + * This is a custom match mode for a non-official format, + * derived from limited (drafting from cubes or custom sets), + * that focuses on allowing the players to cast multicolor + * spells more easily. + *

+ * This is done by having each player conjure a Pillar of the Paruns + * in play on their first turn, instead of their land drop. + * It then lets player play multicolor spells of many combinations, + * in a limited deck, while adding some new layer of strategy + * during the draft. + *

+ * For balance reason, I did introduce the 6 starting hand size, + * as the extra Pillar of the Paruns is like a 7th card, and I + * did not want the player on the draw to discard to handsize. + *

+ * To summarize, this uses the default rules for a 1v1 limited match, + * with two additional custom rules:

+ * -> At the beginning of each player's first main phase, that player + * conjure into play a Pillar of the Paruns. This does count as a + * land drop for the turn.

+ * -> The starting hand size is 6, not 7. + *

+ * I did took the inspiration for the mode from this cube list (not + * sure it is the original source for the idea, but i did not found + * anything else but a youtube video discussing that cube):

+ * https://cubecobra.com/cube/overview/allgoldcube + *

+ * And I am working on a remastered set with:

+ * https://cubecobra.com/cube/overview/parunsmaster + * + * @author Susucr + */ +public class CustomPillarOfTheParunsDuel extends GameImpl { + + public CustomPillarOfTheParunsDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan) { + super(attackOption, range, mulligan, 20, 40, 6); + } + + @Override + protected void init(UUID choosingPlayerId) { + super.init(choosingPlayerId); + + getPlayers().forEach((playerId, p) -> { + addDelayedTriggeredAbility(new AtTheBeginOfPlayerFirstMainPhase(playerId, "Pillar of the Paruns"), null); + }); + + state.getTurnMods().add(new TurnMod(startingPlayerId, PhaseStep.DRAW)); + } + + public CustomPillarOfTheParunsDuel(final CustomPillarOfTheParunsDuel game) { + super(game); + } + + @Override + public MatchType getGameType() { + return new CustomPillarOfTheParunsDuelType(); + } + + @Override + public int getNumPlayers() { + return 2; + } + + @Override + public CustomPillarOfTheParunsDuel copy() { + return new CustomPillarOfTheParunsDuel(this); + } + +} + +class InitPillarOfTheParunsEffect extends OneShotEffect { + + private UUID playerId; + private String cardName; + + InitPillarOfTheParunsEffect(UUID playerId, String cardName){ + super(Outcome.PutLandInPlay); + this.playerId = playerId; + this.cardName = cardName; + this.staticText = "conjure " + cardName + " in play. It does count as a land played for the turn."; + } + + private InitPillarOfTheParunsEffect(final InitPillarOfTheParunsEffect effect){ + super(effect); + this.playerId = effect.playerId; + this.cardName = effect.cardName; + } + + @Override + public InitPillarOfTheParunsEffect copy(){ + return new InitPillarOfTheParunsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source){ + Player player = game.getPlayer(playerId); + if(player == null){ + return false; + } + + new ConjureCardEffect(cardName, Zone.BATTLEFIELD, 1).apply(game, source); + player.incrementLandsPlayed(); + + return true; + } +} + +class AtTheBeginOfPlayerFirstMainPhase extends DelayedTriggeredAbility { + + AtTheBeginOfPlayerFirstMainPhase(UUID playerId, String cardName) { + super(new InitPillarOfTheParunsEffect(playerId, cardName), Duration.Custom, true); + setControllerId(playerId); + setTriggerPhrase("At the beginning of your first main phase, "); + } + + private AtTheBeginOfPlayerFirstMainPhase(final AtTheBeginOfPlayerFirstMainPhase ability) { + super(ability); + } + + @Override + public AtTheBeginOfPlayerFirstMainPhase copy() { + return new AtTheBeginOfPlayerFirstMainPhase(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.PRECOMBAT_MAIN_PHASE_PRE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getPlayerId().equals(getControllerId()); + } +} diff --git a/Mage.Server.Plugins/Mage.Game.CustomPillarOfTheParunsDuel/src/mage/game/CustomPillarOfTheParunsDuelMatch.java b/Mage.Server.Plugins/Mage.Game.CustomPillarOfTheParunsDuel/src/mage/game/CustomPillarOfTheParunsDuelMatch.java new file mode 100644 index 00000000000..595018c9141 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.CustomPillarOfTheParunsDuel/src/mage/game/CustomPillarOfTheParunsDuelMatch.java @@ -0,0 +1,25 @@ +package mage.game; + +import mage.game.match.MatchImpl; +import mage.game.match.MatchOptions; +import mage.game.mulligan.Mulligan; + +/** + * @author Susucr + */ +public class CustomPillarOfTheParunsDuelMatch extends MatchImpl { + + public CustomPillarOfTheParunsDuelMatch(MatchOptions options) { + super(options); + } + + @Override + public void startGame() throws GameException { + Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); + CustomPillarOfTheParunsDuel game = new CustomPillarOfTheParunsDuel(options.getAttackOption(), options.getRange(), mulligan); + game.setStartMessage(this.createGameStartMessage()); + initGame(game); + + games.add(game); + } +} diff --git a/Mage.Server.Plugins/Mage.Game.CustomPillarOfTheParunsDuel/src/mage/game/CustomPillarOfTheParunsDuelType.java b/Mage.Server.Plugins/Mage.Game.CustomPillarOfTheParunsDuel/src/mage/game/CustomPillarOfTheParunsDuelType.java new file mode 100644 index 00000000000..56c1157a04d --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.CustomPillarOfTheParunsDuel/src/mage/game/CustomPillarOfTheParunsDuelType.java @@ -0,0 +1,29 @@ +package mage.game; + +import mage.game.match.MatchType; + +/** + * @author Susucr + */ +public class CustomPillarOfTheParunsDuelType extends MatchType { + + public CustomPillarOfTheParunsDuelType() { + this.name = "Custom Pillar of the Paruns Two Player Duel"; + this.maxPlayers = 2; + this.minPlayers = 2; + this.numTeams = 0; + this.useAttackOption = false; + this.useRange = false; + this.sideboardingAllowed = true; + } + + protected CustomPillarOfTheParunsDuelType(final CustomPillarOfTheParunsDuelType matchType) { + super(matchType); + } + + @Override + public CustomPillarOfTheParunsDuelType copy() { + return new CustomPillarOfTheParunsDuelType(this); + } + +} diff --git a/Mage.Server.Plugins/pom.xml b/Mage.Server.Plugins/pom.xml index dc254573434..a2cf852313a 100644 --- a/Mage.Server.Plugins/pom.xml +++ b/Mage.Server.Plugins/pom.xml @@ -29,6 +29,7 @@ Mage.Game.FreeformCommanderDuel Mage.Game.FreeformCommanderFreeForAll Mage.Game.FreeformUnlimitedCommander + Mage.Game.CustomPillarOfTheParunsDuel Mage.Game.BrawlDuel Mage.Game.BrawlFreeForAll Mage.Game.OathbreakerDuel diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index 199ee37e106..b7708d8250a 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -82,6 +82,7 @@ + diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml index bd4636a455d..343a354227d 100644 --- a/Mage.Server/pom.xml +++ b/Mage.Server/pom.xml @@ -167,6 +167,12 @@ ${project.version} runtime + + ${project.groupId} + mage-game-custompillaroftheparunsduel + ${project.version} + runtime + ${project.groupId} mage-game-oathbreakerduel diff --git a/Mage.Server/src/test/data/config_error.xml b/Mage.Server/src/test/data/config_error.xml index 757bcb5f78d..433918072d4 100644 --- a/Mage.Server/src/test/data/config_error.xml +++ b/Mage.Server/src/test/data/config_error.xml @@ -47,6 +47,7 @@ +