mirror of
https://github.com/magefree/mage.git
synced 2025-12-21 11:02:00 -08:00
* GUI: face down cards improved:
* now it show face up cards in game logs on game end; * now it show face up cards in battlefield on game end (#4635); * fixed that real card face was visible in network data;
This commit is contained in:
parent
6017f35517
commit
4bf3e43da6
4 changed files with 131 additions and 22 deletions
|
|
@ -26,7 +26,7 @@ public class PermanentView extends CardView {
|
||||||
private final boolean summoningSickness;
|
private final boolean summoningSickness;
|
||||||
private final int damage;
|
private final int damage;
|
||||||
private List<UUID> attachments;
|
private List<UUID> attachments;
|
||||||
private final CardView original; // original card before transforms and modifications
|
private final CardView original; // original card before transforms and modifications (null for opponents face down cards)
|
||||||
private final boolean copy;
|
private final boolean copy;
|
||||||
private final String nameOwner; // only filled if != controller
|
private final String nameOwner; // only filled if != controller
|
||||||
private final boolean controlled;
|
private final boolean controlled;
|
||||||
|
|
@ -51,13 +51,17 @@ public class PermanentView extends CardView {
|
||||||
attachments.addAll(permanent.getAttachments());
|
attachments.addAll(permanent.getAttachments());
|
||||||
}
|
}
|
||||||
this.attachedTo = permanent.getAttachedTo();
|
this.attachedTo = permanent.getAttachedTo();
|
||||||
|
|
||||||
|
// show face down cards to all players at the game end
|
||||||
|
boolean showFaceDownInfo = controlled || game.hasEnded();
|
||||||
|
|
||||||
if (isToken()) {
|
if (isToken()) {
|
||||||
original = new CardView(((PermanentToken) permanent).getToken().copy(), (Game) null);
|
original = new CardView(((PermanentToken) permanent).getToken().copy(), (Game) null);
|
||||||
original.expansionSetCode = permanent.getExpansionSetCode();
|
original.expansionSetCode = permanent.getExpansionSetCode();
|
||||||
expansionSetCode = permanent.getExpansionSetCode();
|
expansionSetCode = permanent.getExpansionSetCode();
|
||||||
} else {
|
} else {
|
||||||
if (card != null) {
|
if (card != null && showFaceDownInfo) {
|
||||||
// original may not be face down
|
// face down card must be hidden from opponent, but shown on game end for all
|
||||||
original = new CardView(card.copy(), (Game) null);
|
original = new CardView(card.copy(), (Game) null);
|
||||||
} else {
|
} else {
|
||||||
original = null;
|
original = null;
|
||||||
|
|
@ -71,10 +75,7 @@ public class PermanentView extends CardView {
|
||||||
if (permanent.isCopy() && permanent.isFlipCard()) {
|
if (permanent.isCopy() && permanent.isFlipCard()) {
|
||||||
this.alternateName = permanent.getFlipCardName();
|
this.alternateName = permanent.getFlipCardName();
|
||||||
} else {
|
} else {
|
||||||
if (controlled // controller may always know
|
this.alternateName = original.getName();
|
||||||
|| (!morphed && !manifested)) { // others don't know for morph or transformed cards
|
|
||||||
this.alternateName = original.getName();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (permanent.getOwnerId() != null && !permanent.getOwnerId().equals(permanent.getControllerId())) {
|
if (permanent.getOwnerId() != null && !permanent.getOwnerId().equals(permanent.getControllerId())) {
|
||||||
|
|
@ -88,8 +89,9 @@ public class PermanentView extends CardView {
|
||||||
this.nameOwner = "";
|
this.nameOwner = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add info for face down permanents
|
||||||
if (permanent.isFaceDown(game) && card != null) {
|
if (permanent.isFaceDown(game) && card != null) {
|
||||||
if (controlled) {
|
if (showFaceDownInfo) {
|
||||||
// must be a morphed or manifested card
|
// must be a morphed or manifested card
|
||||||
for (Ability permanentAbility : permanent.getAbilities(game)) {
|
for (Ability permanentAbility : permanent.getAbilities(game)) {
|
||||||
if (permanentAbility.getWorksFaceDown()) {
|
if (permanentAbility.getWorksFaceDown()) {
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,19 @@ import mage.cards.Card;
|
||||||
import mage.constants.EmptyNames;
|
import mage.constants.EmptyNames;
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.view.CardView;
|
||||||
|
import mage.view.GameView;
|
||||||
|
import mage.view.PermanentView;
|
||||||
|
import mage.view.PlayerView;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mage.test.player.TestPlayer;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author LevelX2
|
* @author LevelX2, JayDi85
|
||||||
*/
|
*/
|
||||||
public class ManifestTest extends CardTestPlayerBase {
|
public class ManifestTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
|
@ -474,7 +480,7 @@ public class ManifestTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_ManifestSorceryAndBlinkIt() {
|
public void test_ManifestSorceryAndBlinkIt() {
|
||||||
|
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 1);
|
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 1);
|
||||||
|
|
@ -509,7 +515,7 @@ public class ManifestTest extends CardTestPlayerBase {
|
||||||
setStopAt(2, PhaseStep.END_TURN);
|
setStopAt(2, PhaseStep.END_TURN);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
// no life gain
|
// no life gain
|
||||||
assertLife(playerA, 20);
|
assertLife(playerA, 20);
|
||||||
assertLife(playerB, 20);
|
assertLife(playerB, 20);
|
||||||
|
|
||||||
|
|
@ -524,4 +530,84 @@ public class ManifestTest extends CardTestPlayerBase {
|
||||||
assertHandCount(playerB, "Mountain", 1);
|
assertHandCount(playerB, "Mountain", 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PermanentView findFaceDownPermanent(Game game, TestPlayer viewFromPlayer, TestPlayer searchInPlayer) {
|
||||||
|
Permanent perm = game.getBattlefield().getAllPermanents()
|
||||||
|
.stream()
|
||||||
|
.filter(permanent -> permanent.isFaceDown(game))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
Assert.assertNotNull(perm);
|
||||||
|
GameView gameView = new GameView(game.getState(), game, viewFromPlayer.getId(), null);
|
||||||
|
PlayerView playerView = gameView.getPlayers()
|
||||||
|
.stream()
|
||||||
|
.filter(view -> view.getPlayerId().equals(searchInPlayer.getId()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
Assert.assertNotNull(playerView);
|
||||||
|
PermanentView permanentView = playerView.getBattlefield().values()
|
||||||
|
.stream()
|
||||||
|
.filter(CardView::isFaceDown)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
Assert.assertNotNull(permanentView);
|
||||||
|
return permanentView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertFaceDown(String info, PermanentView faceDownPermanent, String realPermanentName, boolean realInfoMustBeVisible) {
|
||||||
|
if (realInfoMustBeVisible) {
|
||||||
|
// show all info
|
||||||
|
Assert.assertEquals(realPermanentName, faceDownPermanent.getName()); // show real name
|
||||||
|
Assert.assertEquals("2", faceDownPermanent.getPower());
|
||||||
|
Assert.assertEquals("2", faceDownPermanent.getToughness());
|
||||||
|
//
|
||||||
|
Assert.assertNotNull(faceDownPermanent.getOriginal());
|
||||||
|
Assert.assertEquals(realPermanentName, faceDownPermanent.getOriginal().getName());
|
||||||
|
} else {
|
||||||
|
// hide original info
|
||||||
|
Assert.assertEquals(info, "", faceDownPermanent.getName());
|
||||||
|
Assert.assertEquals(info, "2", faceDownPermanent.getPower());
|
||||||
|
Assert.assertEquals(info, "2", faceDownPermanent.getToughness());
|
||||||
|
Assert.assertNull(info, faceDownPermanent.getOriginal());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_FaceDownCardsMustBeVisibleOnGameEnd() {
|
||||||
|
// Exile target creature. Its controller manifests the top card of their library {1}{U}
|
||||||
|
addCard(Zone.HAND, playerA, "Reality Shift");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||||
|
//
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reality Shift", "Silvercoat Lion");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
|
runCode("on active game", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
|
||||||
|
// hide from opponent
|
||||||
|
PermanentView permanent = findFaceDownPermanent(game, playerA, playerB);
|
||||||
|
assertFaceDown("in game: must hide from opponent", permanent, "Mountain", false);
|
||||||
|
|
||||||
|
// show for yourself
|
||||||
|
permanent = findFaceDownPermanent(game, playerB, playerB);
|
||||||
|
assertFaceDown("in game: must show for yourself", permanent, "Mountain", true);
|
||||||
|
});
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
|
||||||
|
// workaround to force end game (can't use other test commands after that)
|
||||||
|
playerA.won(currentGame);
|
||||||
|
Assert.assertTrue(currentGame.hasEnded());
|
||||||
|
|
||||||
|
// show all after game end
|
||||||
|
PermanentView permanent = findFaceDownPermanent(currentGame, playerA, playerB);
|
||||||
|
assertFaceDown("end game: must show for opponent", permanent, "Mountain", true);
|
||||||
|
//
|
||||||
|
permanent = findFaceDownPermanent(currentGame, playerB, playerB);
|
||||||
|
assertFaceDown("end game: must show for yourself", permanent, "Mountain", true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ public class AuratouchedMageTest extends CardTestPlayerBase {
|
||||||
* made the Mage an artifact, for example, you could search for an Aura with
|
* made the Mage an artifact, for example, you could search for an Aura with
|
||||||
* “enchant artifact.” (2005-10-01)
|
* “enchant artifact.” (2005-10-01)
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test // TODO: fix very rare random fails (16 of 1000)
|
||||||
public void testAuratouchedMageEffectHasMadeIntoTypeArtifact() {
|
public void testAuratouchedMageEffectHasMadeIntoTypeArtifact() {
|
||||||
//Expected result: An effect has made Auratouched Mage into an artifact upon entering the battlefield. An aura that only works on artifacts should work.
|
//Expected result: An effect has made Auratouched Mage into an artifact upon entering the battlefield. An aura that only works on artifacts should work.
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
|
|
|
||||||
|
|
@ -675,8 +675,8 @@ public abstract class GameImpl implements Game {
|
||||||
spell = (Spell) obj;
|
spell = (Spell) obj;
|
||||||
} else if (obj != null) {
|
} else if (obj != null) {
|
||||||
logger.error(String.format(
|
logger.error(String.format(
|
||||||
"getSpellOrLKIStack got non-spell id %s correlating to non-spell object %s.",
|
"getSpellOrLKIStack got non-spell id %s correlating to non-spell object %s.",
|
||||||
obj.getClass().getName(), obj.getName()),
|
obj.getClass().getName(), obj.getName()),
|
||||||
new Throwable()
|
new Throwable()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1398,6 +1398,27 @@ public abstract class GameImpl implements Game {
|
||||||
logger.debug("END of gameId: " + this.getId());
|
logger.debug("END of gameId: " + this.getId());
|
||||||
endTime = new Date();
|
endTime = new Date();
|
||||||
state.endGame();
|
state.endGame();
|
||||||
|
|
||||||
|
// inform players about face down cards
|
||||||
|
state.getBattlefield().getAllPermanents()
|
||||||
|
.stream()
|
||||||
|
.filter(permanent -> permanent.isFaceDown(this))
|
||||||
|
.map(permanent -> {
|
||||||
|
Player player = this.getPlayer(permanent.getControllerId());
|
||||||
|
Card card = permanent.getMainCard();
|
||||||
|
if (card != null) {
|
||||||
|
return String.format("Face down card reveal: %s had %s",
|
||||||
|
(player == null ? "Unknown" : player.getLogName()),
|
||||||
|
permanent.getLogName());
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.sorted()
|
||||||
|
.forEach(this::informPlayers);
|
||||||
|
|
||||||
|
// cancel all player dialogs/feedbacks
|
||||||
for (Player player : state.getPlayers().values()) {
|
for (Player player : state.getPlayers().values()) {
|
||||||
player.abort();
|
player.abort();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue