Implement Aeon Engine (#8804)

Co-authored-by: teskogi <tojile7269@yeafam.com>
This commit is contained in:
teskogi 2022-05-25 13:33:28 -07:00 committed by GitHub
parent 015cdf3136
commit 7ec94425df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 238 additions and 3 deletions

View file

@ -0,0 +1,65 @@
package mage.cards.a;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.ExileSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.GameState;
import mage.players.PlayerList;
/**
*
* @author azra1l <algee2005@gmail.com>
*/
public final class AeonEngine extends CardImpl {
public AeonEngine(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}");
// Aeon Engine enters the battlefield tapped.
this.addAbility(new EntersBattlefieldTappedAbility());
// {T}, Exile Aeon Engine: Reverse the game’s turn order. (For example, if play had proceeded clockwise around the table, it now goes counterclockwise.)
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AeonEngineEffect(), new TapSourceCost());
ability.addCost(new ExileSourceCost());
this.addAbility(ability);
}
public AeonEngine(final AeonEngine card) {
super(card);
}
@Override
public AeonEngine copy() {
return new AeonEngine(this);
}
}
class AeonEngineEffect extends OneShotEffect {
public AeonEngineEffect() {
super(Outcome.Benefit);
this.staticText = "Reverse the game turn order.";
}
public AeonEngineEffect(final AeonEngineEffect effect) {
super(effect);
}
public AeonEngineEffect copy() {
return new AeonEngineEffect(this);
}
public boolean apply(Game game, Ability source) {
game.getState().setReverseTurnOrder(true);
return true;
}
}

View file

@ -20,6 +20,7 @@ public final class Commander2019Edition extends ExpansionSet {
this.blockName = "Command Zone";
cards.add(new SetCardInfo("Ainok Survivalist", 156, Rarity.COMMON, mage.cards.a.AinokSurvivalist.class));
cards.add(new SetCardInfo("Aeon Engine", 52, Rarity.RARE, mage.cards.a.AeonEngine.class));
cards.add(new SetCardInfo("Akoum Refuge", 226, Rarity.UNCOMMON, mage.cards.a.AkoumRefuge.class));
cards.add(new SetCardInfo("Alchemist's Greeting", 133, Rarity.COMMON, mage.cards.a.AlchemistsGreeting.class));
cards.add(new SetCardInfo("Angel of Sanctions", 61, Rarity.MYTHIC, mage.cards.a.AngelOfSanctions.class));

View file

@ -0,0 +1,145 @@
package org.mage.test.cards.single.c19;
import java.io.FileNotFoundException;
import mage.constants.MultiplayerAttackOption;
import mage.constants.PhaseStep;
import mage.constants.RangeOfInfluence;
import mage.constants.Zone;
import mage.game.FreeForAll;
import mage.game.Game;
import mage.game.GameException;
import mage.game.mulligan.MulliganType;
import mage.players.Player;
import org.junit.Test;
import org.mage.test.player.TestPlayer;
import org.mage.test.serverside.base.CardTestMultiPlayerBase;
/**
*
* @author azra1l <algee2005@gmail.com>
*/
public class AeonEngineTest extends CardTestMultiPlayerBase {
@Override
protected Game createNewGameAndPlayers() throws GameException {
Game game = new FreeForAll(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
// Player order: A -> D -> C -> B
playerA = createPlayer(game, playerA, "PlayerA");
playerB = createPlayer(game, playerB, "PlayerB");
playerC = createPlayer(game, playerC, "PlayerC");
playerD = createPlayer(game, playerD, "PlayerD");
return game;
}
@Test
public void testEnterTappedNormalTurnOrder() {
// Aeon Engine - Artefact - {5}
// Aeon Engine enters the battlefield tapped.
// {T}, Exile Aeon Engine: Reverse the game’s turn order. (For example, if play had proceeded clockwise around the table, it now goes counterclockwise.)
addCard(Zone.HAND, playerA, "Aeon Engine", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5);
addCard(Zone.HAND, playerD, "Agonizing Syphon", 1);
addCard(Zone.BATTLEFIELD, playerD, "Swamp", 4);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Aeon Engine");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, "Agonizing Syphon", playerA);
setStrictChooseMode(true);
setStopAt(2, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
//check if aeon engine is tapped
assertTapped("Aeon Engine", true);
//check if turn was passed to correct player - should be D
assertActivePlayer(playerD);
assertLife(playerA, 17);
assertLife(playerD, 23);
}
@Test
public void testExileCostReversedTurnOrder() throws GameException, FileNotFoundException {
// Aeon Engine - Artefact - {5}
// Aeon Engine enters the battlefield tapped.
// {T}, Exile Aeon Engine: Reverse the game’s turn order. (For example, if play had proceeded clockwise around the table, it now goes counterclockwise.)
addCard(Zone.HAND, playerB, "Agonizing Syphon", 3);
addCard(Zone.HAND, playerA, "Aeon Engine", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5);
addCard(Zone.HAND, playerB, "Agonizing Syphon", 3);
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 5);
addCard(Zone.HAND, playerC, "Agonizing Syphon", 3);
addCard(Zone.BATTLEFIELD, playerC, "Swamp", 5);
addCard(Zone.HAND, playerD, "Agonizing Syphon", 3);
addCard(Zone.BATTLEFIELD, playerD, "Swamp", 5);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Aeon Engine");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, "Agonizing Syphon", playerA);
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerC, "Agonizing Syphon", playerA);
castSpell(4, PhaseStep.PRECOMBAT_MAIN, playerB, "Agonizing Syphon", playerA);
activateAbility(5, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}, Exile {this}:");
castSpell(6, PhaseStep.PRECOMBAT_MAIN, playerB, "Agonizing Syphon", playerA);
setStrictChooseMode(true);
setStopAt(6, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
//check if aeon engine has been exiled
assertExileCount(playerA, "Aeon Engine", 1);
//check if turn was passed to correct player each turn - should be B
assertActivePlayer(playerB);
assertLife(playerA, 8);
assertLife(playerB, 26);
assertLife(playerC, 23);
assertLife(playerD, 23);
assertGraveyardCount(playerB, "Agonizing Syphon", 2);
assertGraveyardCount(playerC, "Agonizing Syphon", 1);
assertGraveyardCount(playerD, "Agonizing Syphon", 1);
}
@Test
public void testExileCostReversedTurnOrderDouble() throws GameException, FileNotFoundException {
// Aeon Engine - Artefact - {5}
// Aeon Engine enters the battlefield tapped.
// {T}, Exile Aeon Engine: Reverse the game’s turn order. (For example, if play had proceeded clockwise around the table, it now goes counterclockwise.)
addCard(Zone.HAND, playerA, "Agonizing Syphon", 3);
addCard(Zone.HAND, playerA, "Aeon Engine", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5);
addCard(Zone.HAND, playerB, "Agonizing Syphon", 3);
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 5);
addCard(Zone.HAND, playerC, "Agonizing Syphon", 3);
addCard(Zone.BATTLEFIELD, playerC, "Swamp", 5);
addCard(Zone.HAND, playerD, "Agonizing Syphon", 3);
addCard(Zone.HAND, playerD, "Aeon Engine", 1);
addCard(Zone.BATTLEFIELD, playerD, "Swamp", 5);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Aeon Engine");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, "Aeon Engine");
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerC, "Agonizing Syphon", playerA);
castSpell(4, PhaseStep.PRECOMBAT_MAIN, playerB, "Agonizing Syphon", playerA);
activateAbility(5, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}, Exile {this}:");
castSpell(6, PhaseStep.PRECOMBAT_MAIN, playerB, "Agonizing Syphon", playerA);
castSpell(7, PhaseStep.PRECOMBAT_MAIN, playerC, "Agonizing Syphon", playerA);
activateAbility(8, PhaseStep.PRECOMBAT_MAIN, playerD, "{T}, Exile {this}:");
castSpell(9, PhaseStep.PRECOMBAT_MAIN, playerC, "Agonizing Syphon", playerA);
setStrictChooseMode(true);
setStopAt(9, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
//check if aeon engine's have been exiled
assertExileCount(playerA, "Aeon Engine", 1);
assertExileCount(playerD, "Aeon Engine", 1);
//check if turn was passed to correct player each turn - should be C
assertActivePlayer(playerC);
assertLife(playerA, 5);
assertLife(playerB, 26);
assertLife(playerC, 29);
assertLife(playerD, 20);
assertGraveyardCount(playerB, "Agonizing Syphon", 2);
assertGraveyardCount(playerC, "Agonizing Syphon", 3);
}
}

View file

@ -647,4 +647,6 @@ public interface Game extends MageItem, Serializable, Copyable<Game> {
void setGameStopped(boolean gameStopped);
boolean isGameStopped();
boolean isTurnOrderReversed();
}

View file

@ -3770,6 +3770,11 @@ public abstract class GameImpl implements Game {
return gameStopped;
}
@Override
public boolean isTurnOrderReversed() {
return state.getReverseTurnOrder();
}
@Override
public String toString() {
Player activePayer = this.getPlayer(this.getActivePlayerId());

View file

@ -108,6 +108,7 @@ public class GameState implements Serializable, Copyable<GameState> {
private boolean manaBurn = false;
private boolean hasDayNight = false;
private boolean isDaytime = true;
private boolean reverseTurnOrder = false;
private int applyEffectsCounter; // Upcounting number of each applyEffects execution
@ -1449,4 +1450,16 @@ public class GameState implements Serializable, Copyable<GameState> {
public String toString() {
return CardUtil.getTurnInfo(this);
}
public boolean setReverseTurnOrder(boolean reverse){
if(this.reverseTurnOrder&&reverse){
this.reverseTurnOrder = false;
} else {
this.reverseTurnOrder = reverse;
}
return this.reverseTurnOrder;
}
public boolean getReverseTurnOrder(){
return this.reverseTurnOrder;
}
}

View file

@ -47,7 +47,11 @@ public class PlayerList extends CircularList<UUID> {
}
Player player;
while (true) {
player = game.getPlayer(super.getNext());
if(game.isTurnOrderReversed()){
player = game.getPlayer(super.getPrevious());
} else{
player = game.getPlayer(super.getNext());
}
if (player.isInGame()) {
break;
}