mirror of
https://github.com/correl/mage.git
synced 2024-11-14 11:09:31 +00:00
Tokens rework:
- tests: added support of set code in custom ability (see addCustomCardWithAbility); - tests: added additional tests for token images (related to #10139, #10222); - fixed wrong token images for copied cards/tokens (#10222);
This commit is contained in:
parent
5c6de9815f
commit
94819ff91c
5 changed files with 149 additions and 12 deletions
|
@ -9,6 +9,7 @@ import mage.cards.repository.TokenRepository;
|
|||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.game.permanent.token.SoldierToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.game.permanent.token.TokenImpl;
|
||||
import mage.game.permanent.token.custom.CreatureToken;
|
||||
|
@ -129,16 +130,19 @@ public class TokenImagesTest extends CardTestPlayerBase {
|
|||
|
||||
private void assert_Inner(String cardName, int cardAmountInExile, int cardAmountInGrave, int cardAmountInBattlefield,
|
||||
String tokenName, int tokenAmount, boolean mustStoreAsCard, String... checks) {
|
||||
assertExileCount(playerA, cardName, cardAmountInExile);
|
||||
assertGraveyardCount(playerA, cardName, cardAmountInGrave);
|
||||
assertPermanentCount(playerA, cardName, cardAmountInBattlefield);
|
||||
assertPermanentCount(playerA, tokenName, tokenAmount);
|
||||
if (!cardName.isEmpty()) {
|
||||
assertExileCount(playerA, cardName, cardAmountInExile);
|
||||
assertGraveyardCount(playerA, cardName, cardAmountInGrave);
|
||||
assertPermanentCount(playerA, cardName, cardAmountInBattlefield);
|
||||
}
|
||||
assertTokenCount(playerA, tokenName, tokenAmount);
|
||||
|
||||
// collect real server stats
|
||||
Map<String, List<Card>> realServerStats = new LinkedHashMap<>();
|
||||
currentGame.getBattlefield().getAllPermanents()
|
||||
.stream()
|
||||
.filter(card -> card.getName().equals(tokenName))
|
||||
.filter(card -> card instanceof PermanentToken)
|
||||
.sorted(Comparator.comparing(Card::getExpansionSetCode))
|
||||
.forEach(card -> {
|
||||
Assert.assertNotNull("must have set code", card.getExpansionSetCode());
|
||||
|
@ -159,6 +163,7 @@ public class TokenImagesTest extends CardTestPlayerBase {
|
|||
playerView.getBattlefield().values()
|
||||
.stream()
|
||||
.filter(card -> card.getName().equals(tokenName))
|
||||
.filter(CardView::isToken)
|
||||
.sorted(Comparator.comparing(CardView::getExpansionSetCode))
|
||||
.forEach(permanentView -> {
|
||||
String realCode = permanentView.getExpansionSetCode();
|
||||
|
@ -338,6 +343,93 @@ public class TokenImagesTest extends CardTestPlayerBase {
|
|||
assert_TheHive(20, "5ED=0", "10E>0", "30A>0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_TokenExists_MustGetSameImageForAllTokenInstances() {
|
||||
Ability ability = new SimpleActivatedAbility(
|
||||
Zone.ALL,
|
||||
new CreateTokenEffect(new SoldierToken(), 10),
|
||||
new ManaCostsImpl<>("")
|
||||
);
|
||||
addCustomCardWithAbility("40K-test", playerA, ability);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "create ten");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, 1 + 10); // 1 test card + 10 tokens
|
||||
assert_TokenTypes("Soldier Token", 1); // one ability's call must generate tokens with same image
|
||||
assert_Inner("test", 0, 0, 1,
|
||||
"Soldier Token", 10, false, "40K=10");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_TokenExists_CopyMustGetSameImageAsCopiedCard() {
|
||||
// copied cards
|
||||
// https://github.com/magefree/mage/issues/10222
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "NEC-Silver Myr", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "MM2-Alloy Myr", 3);
|
||||
//
|
||||
// Choose target artifact creature you control. For each creature chosen this way, create a token that's a copy of it.
|
||||
// Overload {6}{U} (You may cast this spell for its overload cost. If you do, change its text by replacing all instances of "target" with "each.")
|
||||
addCard(Zone.HAND, playerA, "BRC-March of Progress", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 7);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "March of Progress with overload");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
// +3 new tokens for each
|
||||
assertPermanentCount(playerA, "Silver Myr", 3 + 3);
|
||||
assertPermanentCount(playerA, "Alloy Myr", 3 + 3);
|
||||
|
||||
// tokens must use same set code as copied card
|
||||
assert_Inner("Silver Myr", 0, 0, 3 + 3,
|
||||
"Silver Myr", 3, true, "NEC=3");
|
||||
assert_Inner("Alloy Myr", 0, 0, 3 + 3,
|
||||
"Alloy Myr", 3, true, "MM2=3");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_TokenExists_CopyMustGetSameImageAsCopiedToken() {
|
||||
// copied tokens
|
||||
// https://github.com/magefree/mage/issues/10222
|
||||
|
||||
// -2: Create a 0/0 colorless Construct artifact creature token with "This creature gets +1/+1 for each artifact you control."
|
||||
addCard(Zone.BATTLEFIELD, playerA, "MED-Karn, Scion of Urza", 1);
|
||||
//
|
||||
// Choose target artifact creature you control. For each creature chosen this way, create a token that's a copy of it.
|
||||
// Overload {6}{U} (You may cast this spell for its overload cost. If you do, change its text by replacing all instances of "target" with "each.")
|
||||
addCard(Zone.HAND, playerA, "BRC-March of Progress", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 7);
|
||||
|
||||
// prepare token
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-2:");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkPermanentCount("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Construct Token", 1);
|
||||
|
||||
// copy token
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "March of Progress with overload");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
// +1 new token
|
||||
assertPermanentCount(playerA, "Construct Token", 1 + 1);
|
||||
|
||||
// tokens must use same set code as copied token
|
||||
assert_Inner("", 0, 0, 0,
|
||||
"Construct Token", 2, false, "MED=2");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
// TODO: implement auto-generate creature token images from public tokens (by name, type, color, PT, abilities)
|
||||
|
|
|
@ -171,6 +171,15 @@ public interface CardTestAPI {
|
|||
*/
|
||||
void assertPermanentCount(Player player, String cardName, int count) throws AssertionError;
|
||||
|
||||
/**
|
||||
* Assert token count under player's control.
|
||||
*
|
||||
* @param player {@link Player} which permanents should be counted.
|
||||
* @param tokenName Name of the tokens that should be counted.
|
||||
* @param count Expected count.
|
||||
*/
|
||||
void assertTokenCount(Player player, String tokenName, int count) throws AssertionError;
|
||||
|
||||
/**
|
||||
* Assert command zone object count in player's command zone
|
||||
*
|
||||
|
|
|
@ -35,6 +35,7 @@ import mage.server.managers.ConfigSettings;
|
|||
import mage.server.util.ConfigFactory;
|
||||
import mage.server.util.ConfigWrapper;
|
||||
import mage.server.util.PluginClassLoader;
|
||||
import mage.server.util.SystemUtil;
|
||||
import mage.server.util.config.GamePlugin;
|
||||
import mage.server.util.config.Plugin;
|
||||
import mage.target.TargetPermanent;
|
||||
|
@ -425,12 +426,19 @@ public abstract class MageTestPlayerBase {
|
|||
|
||||
protected void addCustomCardWithAbility(String customName, TestPlayer controllerPlayer, Ability ability, SpellAbility spellAbility,
|
||||
CardType cardType, String spellCost, Zone putAtZone, SubType... additionalSubTypes) {
|
||||
CustomTestCard.clearCustomAbilities(customName);
|
||||
CustomTestCard.addCustomAbility(customName, spellAbility, ability);
|
||||
CustomTestCard.clearAdditionalSubtypes(customName);
|
||||
CustomTestCard.addAdditionalSubtypes(customName, additionalSubTypes);
|
||||
List<String> cardCommand = SystemUtil.parseSetAndCardNameCommand(customName);
|
||||
String needSetCode = cardCommand.get(0);
|
||||
String needCardName = cardCommand.get(1);
|
||||
if (needSetCode.isEmpty()) {
|
||||
needSetCode = "custom";
|
||||
}
|
||||
|
||||
CardSetInfo testSet = new CardSetInfo(customName, "custom", "123", Rarity.COMMON);
|
||||
CustomTestCard.clearCustomAbilities(needCardName);
|
||||
CustomTestCard.addCustomAbility(needCardName, spellAbility, ability);
|
||||
CustomTestCard.clearAdditionalSubtypes(needCardName);
|
||||
CustomTestCard.addAdditionalSubtypes(needCardName, additionalSubTypes);
|
||||
|
||||
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);
|
||||
|
|
|
@ -21,6 +21,7 @@ import mage.game.command.CommandObject;
|
|||
import mage.game.match.MatchOptions;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.player.ai.ComputerPlayer7;
|
||||
import mage.player.ai.ComputerPlayerMCTS;
|
||||
import mage.players.ManaPool;
|
||||
|
@ -623,7 +624,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
}
|
||||
|
||||
// set code for card
|
||||
String setCode = "";
|
||||
String setCode;
|
||||
List<String> cardCommand = SystemUtil.parseSetAndCardNameCommand(cardName);
|
||||
setCode = cardCommand.get(0);
|
||||
cardName = cardCommand.get(1);
|
||||
|
@ -966,6 +967,22 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
Assert.assertEquals("(Battlefield) Permanents counts for " + player.getName() + " are not equal (" + cardName + ')', count, actualCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertTokenCount(Player player, String tokenName, int count) throws AssertionError {
|
||||
//Assert.assertNotEquals("", tokenName);
|
||||
int actualCount = 0;
|
||||
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
|
||||
if (permanent instanceof PermanentToken) {
|
||||
if (permanent.getControllerId().equals(player.getId())) {
|
||||
if (isObjectHaveTargetNameOrAlias(player, permanent, tokenName)) {
|
||||
actualCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Assert.assertEquals("(Battlefield) Tokens counts for " + player.getName() + " are not equal (" + tokenName + ')', count, actualCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertCommandZoneCount(Player player, String commandZoneObjectName, int count) throws AssertionError {
|
||||
//Assert.assertNotEquals("", commandZoneObjectName);
|
||||
|
|
|
@ -156,11 +156,22 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
|
|||
// - use random set code
|
||||
// - use default set code
|
||||
|
||||
// token from a card - must use card image instead (example: Embalm ability)
|
||||
if (token.getOriginalCardNumber() != null) {
|
||||
// token from a card, so must use card image instead (example: Embalm ability)
|
||||
return new TokenInfo(TokenType.TOKEN, token.getName(), token.getOriginalExpansionSetCode(), 0);
|
||||
}
|
||||
|
||||
// token from another token
|
||||
if (token instanceof EmptyToken) {
|
||||
if (token.getOriginalExpansionSetCode() == null) {
|
||||
// possible reason: miss call of CardUtil.copySetAndCardNumber in copying method
|
||||
throw new IllegalArgumentException("Wrong code usage: can't copy token without set code");
|
||||
}
|
||||
return new TokenInfo(TokenType.TOKEN, token.getName(), token.getOriginalExpansionSetCode(), token.getTokenType());
|
||||
}
|
||||
|
||||
// token as is
|
||||
|
||||
// source
|
||||
final String setCode;
|
||||
Card sourceCard = game.getCard(sourceId);
|
||||
|
@ -272,8 +283,8 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
|
|||
List<Permanent> allowedTokens = new ArrayList<>();
|
||||
|
||||
// prepare tokens to enter
|
||||
// must use same image for all tokens
|
||||
for (int i = 0; i < amount; i++) {
|
||||
// TODO: add random setTokenType here?
|
||||
// use event.getPlayerId() as controller because it can be replaced by replacement effect
|
||||
PermanentToken newPermanent = new PermanentToken(token, event.getPlayerId(), game);
|
||||
game.getState().addCard(newPermanent);
|
||||
|
|
Loading…
Reference in a new issue