mirror of
https://github.com/magefree/mage.git
synced 2025-12-28 14:32:06 -08:00
game engine, tests and other fixes:
tests: fixed wrong permanent structure for battlefield cards (addCard command); tests: added docs and additional runtime checks; game: Modal double-faced cards - improved support, no more other side effects on battlefield; game: Copy abilities - improved stability and cards support; game: Player under control - improved stability and related cards support (possible NPE errors, additional runtime checks); server: fixed bloated logs with game timer; AI: fixed wrong timer in computer games;
This commit is contained in:
parent
824e4c6b7a
commit
229e8d3075
35 changed files with 303 additions and 151 deletions
|
|
@ -889,9 +889,10 @@ public class CopySpellTest extends CardTestPlayerBase {
|
|||
}
|
||||
|
||||
private void prepareZoneAndZCC(Card originalCard) {
|
||||
// prepare custom zcc and zone for copy testing
|
||||
// prepare custom zcc and zone for copy testing (it's not real game)
|
||||
// HAND zone is safest way (some card types require diff zones for stack/battlefield, e.g. MDFC)
|
||||
originalCard.setZoneChangeCounter(5, currentGame);
|
||||
originalCard.setZone(Zone.STACK, currentGame);
|
||||
originalCard.setZone(Zone.HAND, currentGame);
|
||||
}
|
||||
|
||||
private void cardsMustHaveSameZoneAndZCC(Card originalCard, Card copiedCard, String infoPrefix) {
|
||||
|
|
|
|||
|
|
@ -999,4 +999,33 @@ public class ModalDoubleFacedCardsTest extends CardTestPlayerBase {
|
|||
setStopAt(2, PhaseStep.END_TURN);
|
||||
execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Battlefield_MustHaveAbilitiesFromOneSideOnly() {
|
||||
// possible bug: test framework adds second side abilities
|
||||
|
||||
// left side - Reidane, God of the Worthy:
|
||||
// Snow lands your opponents control enter the battlefield tapped.
|
||||
// right side - Valkmira, Protector's Shield:
|
||||
// If a source an opponent controls would deal damage to you or a permanent you control, prevent 1 of that damage.
|
||||
// Whenever you or another permanent you control becomes the target of a spell or ability an opponent controls,
|
||||
// counter that spell or ability unless its controller pays {1}.
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Reidane, God of the Worthy", 1);
|
||||
//
|
||||
addCard(Zone.HAND, playerA, "Snow-Covered Forest", 1);
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
|
||||
// cast, second side effects must be ignored (e.g. counter trigger)
|
||||
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snow-Covered Forest");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt");
|
||||
addTarget(playerA, playerB);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertTappedCount("Snow-Covered Forest", true, 1);
|
||||
assertLife(playerB, 20 - 3);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import mage.cards.repository.CardRepository;
|
|||
import mage.constants.*;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.PutToBattlefieldInfo;
|
||||
import mage.game.match.Match;
|
||||
import mage.game.match.MatchType;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
|
|
@ -72,7 +73,7 @@ public abstract class MageTestPlayerBase {
|
|||
protected Pattern pattern = Pattern.compile("([a-zA-Z]*):([\\w]*):([a-zA-Z ,\\-.!'\\d]*):([\\d]*)(:\\{tapped\\})?");
|
||||
|
||||
protected Map<TestPlayer, List<Card>> handCards = new HashMap<>();
|
||||
protected Map<TestPlayer, List<PermanentCard>> battlefieldCards = new HashMap<>();
|
||||
protected Map<TestPlayer, List<PutToBattlefieldInfo>> battlefieldCards = new HashMap<>(); // cards + additional status like tapped
|
||||
protected Map<TestPlayer, List<Card>> graveyardCards = new HashMap<>();
|
||||
protected Map<TestPlayer, List<Card>> libraryCards = new HashMap<>();
|
||||
protected Map<TestPlayer, List<Card>> commandCards = new HashMap<>();
|
||||
|
|
@ -111,7 +112,7 @@ public abstract class MageTestPlayerBase {
|
|||
EXPECTED
|
||||
}
|
||||
|
||||
protected ParserState parserState;
|
||||
protected ParserState parserState; // TODO: remove outdated and unsued code
|
||||
|
||||
/**
|
||||
* Expected results of the test. Read from test case in {@link String} based
|
||||
|
|
@ -216,6 +217,7 @@ public abstract class MageTestPlayerBase {
|
|||
}
|
||||
|
||||
private void parseLine(String line) {
|
||||
// TODO: delete unused code
|
||||
if (parserState == ParserState.EXPECTED) {
|
||||
expectedResults.add(line); // just remember for future use
|
||||
return;
|
||||
|
|
@ -229,14 +231,14 @@ public abstract class MageTestPlayerBase {
|
|||
|
||||
if (nickname.startsWith("Computer")) {
|
||||
List<Card> cards = null;
|
||||
List<PermanentCard> perms = null;
|
||||
//List<PermanentCard> perms = null;
|
||||
Zone gameZone;
|
||||
if ("hand".equalsIgnoreCase(zone)) {
|
||||
gameZone = Zone.HAND;
|
||||
cards = getHandCards(getPlayer(nickname));
|
||||
} else if ("battlefield".equalsIgnoreCase(zone)) {
|
||||
gameZone = Zone.BATTLEFIELD;
|
||||
perms = getBattlefieldCards(getPlayer(nickname));
|
||||
//perms = getBattlefieldCards(getPlayer(nickname));
|
||||
} else if ("graveyard".equalsIgnoreCase(zone)) {
|
||||
gameZone = Zone.GRAVEYARD;
|
||||
cards = getGraveCards(getPlayer(nickname));
|
||||
|
|
@ -268,10 +270,10 @@ public abstract class MageTestPlayerBase {
|
|||
Card newCard = cardInfo != null ? cardInfo.getCard() : null;
|
||||
if (newCard != null) {
|
||||
if (gameZone == Zone.BATTLEFIELD) {
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||
PermanentCard p = new PermanentCard(permCard, null, currentGame);
|
||||
p.setTapped(tapped);
|
||||
perms.add(p);
|
||||
//Card permCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||
//PermanentCard p = new PermanentCard(permCard, null, currentGame);
|
||||
//p.setTapped(tapped);
|
||||
//perms.add(p);
|
||||
} else {
|
||||
cards.add(newCard);
|
||||
}
|
||||
|
|
@ -339,11 +341,11 @@ public abstract class MageTestPlayerBase {
|
|||
return res;
|
||||
}
|
||||
|
||||
protected List<PermanentCard> getBattlefieldCards(TestPlayer player) {
|
||||
protected List<PutToBattlefieldInfo> getBattlefieldCards(TestPlayer player) {
|
||||
if (battlefieldCards.containsKey(player)) {
|
||||
return battlefieldCards.get(player);
|
||||
}
|
||||
List<PermanentCard> res = new ArrayList<>();
|
||||
List<PutToBattlefieldInfo> res = new ArrayList<>();
|
||||
battlefieldCards.put(player, res);
|
||||
return res;
|
||||
}
|
||||
|
|
@ -437,12 +439,13 @@ public abstract class MageTestPlayerBase {
|
|||
|
||||
CardSetInfo testSet = new CardSetInfo(needCardName, needSetCode, "123", Rarity.COMMON);
|
||||
Card newCard = new CustomTestCard(controllerPlayer.getId(), testSet, cardType, spellCost);
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||
PermanentCard permanent = new PermanentCard(permCard, controllerPlayer.getId(), currentGame);
|
||||
|
||||
switch (putAtZone) {
|
||||
case BATTLEFIELD:
|
||||
getBattlefieldCards(controllerPlayer).add(permanent);
|
||||
getBattlefieldCards(controllerPlayer).add(new PutToBattlefieldInfo(
|
||||
newCard,
|
||||
false
|
||||
));
|
||||
break;
|
||||
case GRAVEYARD:
|
||||
getGraveCards(controllerPlayer).add(newCard);
|
||||
|
|
@ -565,7 +568,7 @@ public abstract class MageTestPlayerBase {
|
|||
}
|
||||
}
|
||||
|
||||
// custom card with global abilities list to init (can contains abilities per card name)
|
||||
// custom card with global abilities list to init (can contain abilities per card name)
|
||||
class CustomTestCard extends CardImpl {
|
||||
|
||||
static private final Map<String, Abilities<Ability>> abilitiesList = new HashMap<>(); // card name -> abilities
|
||||
|
|
|
|||
|
|
@ -631,7 +631,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
}
|
||||
|
||||
/**
|
||||
* Add any amount of cards to specified zone of specified player.
|
||||
* Add any amount of cards to specified zone of specified player without resolve/ETB
|
||||
*
|
||||
* @param gameZone {@link mage.constants.Zone} to add cards to.
|
||||
* @param player {@link Player} to add cards for. Use either playerA or
|
||||
|
|
@ -684,14 +684,13 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
if (gameZone == Zone.BATTLEFIELD) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
Card newCard = cardInfo.getCard();
|
||||
Card permCard = CardUtil.getDefaultCardSideForBattlefield(currentGame, newCard);
|
||||
|
||||
PermanentCard p = new PermanentCard(permCard, player.getId(), currentGame);
|
||||
p.setTapped(tapped);
|
||||
getBattlefieldCards(player).add(p);
|
||||
|
||||
getBattlefieldCards(player).add(new PutToBattlefieldInfo(
|
||||
newCard,
|
||||
tapped
|
||||
));
|
||||
if (!aliasName.isEmpty()) {
|
||||
player.addAlias(player.generateAliasName(aliasName, useAliasMultiNames, i + 1), p.getId());
|
||||
// TODO: is it bugged with double faced cards (wrong ref)?
|
||||
player.addAlias(player.generateAliasName(aliasName, useAliasMultiNames, i + 1), newCard.getId());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -78,14 +78,16 @@ public class AddCardApiTest extends CardTestPlayerBase {
|
|||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Memorial to Glory", 2);
|
||||
getBattlefieldCards(playerA).stream()
|
||||
.filter(card -> card.getName().equals("Memorial to Glory"))
|
||||
.forEach(card -> Assert.assertEquals("40K", card.getExpansionSetCode()));
|
||||
getBattlefieldCards(playerA)
|
||||
.stream()
|
||||
.filter(info -> info.getCard().getName().equals("Memorial to Glory"))
|
||||
.forEach(info -> Assert.assertEquals("40K", info.getCard().getExpansionSetCode()));
|
||||
|
||||
assertPermanentCount(playerA, "Plains", 2);
|
||||
getBattlefieldCards(playerA).stream()
|
||||
.filter(card -> card.getName().equals("Plains"))
|
||||
.forEach(card -> Assert.assertEquals("PANA", card.getExpansionSetCode()));
|
||||
getBattlefieldCards(playerA)
|
||||
.stream()
|
||||
.filter(info -> info.getCard().getName().equals("Plains"))
|
||||
.forEach(info -> Assert.assertEquals("PANA", info.getCard().getExpansionSetCode()));
|
||||
}
|
||||
|
||||
@Test(expected = org.junit.ComparisonFailure.class)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ public class ExtraTurnsTest extends CardTestPlayerBase {
|
|||
private void checkTurnControl(int turn, TestPlayer needTurnController, boolean isExtraTurn) {
|
||||
runCode("checking turn " + turn, turn, PhaseStep.POSTCOMBAT_MAIN, playerA, (info, player, game) -> {
|
||||
Player defaultTurnController = game.getPlayer(game.getActivePlayerId());
|
||||
Player realTurnController = defaultTurnController.getTurnControlledBy() == null ? defaultTurnController : game.getPlayer(defaultTurnController.getTurnControlledBy());
|
||||
Player realTurnController = game.getPlayer(defaultTurnController.getTurnControlledBy());
|
||||
Assert.assertEquals(String.format("turn %d must be controlled by %s", turn, needTurnController.getName()),
|
||||
needTurnController.getName(), realTurnController.getName());
|
||||
Assert.assertEquals(String.format("turn %d must be %s", turn, (isExtraTurn ? "extra turn" : "normal turn")),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue