Dungeon improves:

* Dungeons: added dungeon name hint to room's game log and choices (part of #12274);
* GUI, game: added card popup hints support in feedback panel (yes/no choices);
* Images: fixed miss images for dungeons in command zone, game logs and choice dialogs;
This commit is contained in:
Oleg Agafonov 2024-09-19 13:42:23 +04:00
parent cd51954208
commit b40e7222b3
9 changed files with 94 additions and 26 deletions

View file

@ -8,10 +8,12 @@ import mage.client.cards.BigCard;
import mage.client.cards.VirtualCardInfo; import mage.client.cards.VirtualCardInfo;
import mage.client.dialog.PreferencesDialog; import mage.client.dialog.PreferencesDialog;
import mage.client.game.GamePanel; import mage.client.game.GamePanel;
import mage.game.command.Dungeon;
import mage.game.command.Plane; import mage.game.command.Plane;
import mage.util.CardUtil; import mage.util.CardUtil;
import mage.util.GameLog; import mage.util.GameLog;
import mage.view.CardView; import mage.view.CardView;
import mage.view.DungeonView;
import mage.view.PlaneView; import mage.view.PlaneView;
import javax.swing.*; import javax.swing.*;
@ -156,7 +158,7 @@ public class MageEditorPane extends JEditorPane {
// show real object by priority (workable card hints and actual info) // show real object by priority (workable card hints and actual info)
CardView cardView = needCard; CardView cardView = needCard;
// if no game object found then show default card // if no game object found then show default card/object
if (cardView == null) { if (cardView == null) {
CardInfo card = CardRepository.instance.findCards(cardName).stream().findFirst().orElse(null); CardInfo card = CardRepository.instance.findCards(cardName).stream().findFirst().orElse(null);
if (card != null) { if (card != null) {
@ -172,6 +174,14 @@ public class MageEditorPane extends JEditorPane {
} }
} }
// dungeon
if (cardView == null) {
Dungeon dungeon = Dungeon.createDungeon(cardName, false);
if (dungeon != null) {
cardView = new CardView(new DungeonView(dungeon));
}
}
// TODO: add other objects like dungeon, emblem, commander // TODO: add other objects like dungeon, emblem, commander
if (cardView != null) { if (cardView != null) {

View file

@ -314,7 +314,7 @@ public class PickChoiceDialog extends MageDialog {
cardInfo.init(item.getHint(), this.bigCard, this.gameId); cardInfo.init(item.getHint(), this.bigCard, this.gameId);
} else if (item.getHintType() == ChoiceHintType.CARD_DUNGEON) { } else if (item.getHintType() == ChoiceHintType.CARD_DUNGEON) {
// as card name // as card name
CardView cardView = new CardView(new DungeonView(Dungeon.createDungeon(item.getHint()))); CardView cardView = new CardView(new DungeonView(Dungeon.createDungeon(item.getHint(), true)));
cardInfo.init(cardView, this.bigCard, this.gameId); cardInfo.init(cardView, this.bigCard, this.gameId);
} else if (item.getHintType() == ChoiceHintType.GAME_OBJECT) { } else if (item.getHintType() == ChoiceHintType.GAME_OBJECT) {
// as object // as object

View file

@ -2,6 +2,7 @@ package mage.client.game;
import mage.client.MageFrame; import mage.client.MageFrame;
import mage.client.SessionHandler; import mage.client.SessionHandler;
import mage.client.cards.BigCard;
import mage.client.chat.ChatPanelBasic; import mage.client.chat.ChatPanelBasic;
import mage.client.dialog.MageDialog; import mage.client.dialog.MageDialog;
import mage.client.util.audio.AudioManager; import mage.client.util.audio.AudioManager;
@ -56,9 +57,9 @@ public class FeedbackPanel extends javax.swing.JPanel {
customInitComponents(); customInitComponents();
} }
public void init(UUID gameId) { public void init(UUID gameId, BigCard bigCard) {
this.gameId = gameId; this.gameId = gameId;
helper.init(gameId); helper.init(gameId, bigCard);
setGUISize(); setGUISize();
} }

View file

@ -196,11 +196,20 @@ public final class GamePanel extends javax.swing.JPanel {
player.getGraveyard().values().forEach(c -> this.allCardsIndex.put(c.getId(), c)); player.getGraveyard().values().forEach(c -> this.allCardsIndex.put(c.getId(), c));
Optional.ofNullable(player.getTopCard()).ifPresent(c -> this.allCardsIndex.put(c.getId(), c)); Optional.ofNullable(player.getTopCard()).ifPresent(c -> this.allCardsIndex.put(c.getId(), c));
// TODO: add support of dungeon, emblem all another non-card objects // TODO: add support of dungeon, emblem all another non-card objects
// commanders and custom emblems
player.getCommandObjectList() player.getCommandObjectList()
.stream() .forEach(object -> {
.filter(c -> c instanceof CardView) if (object instanceof CardView) {
.map(c -> (CardView) c) // commanders and custom emblems
.forEach(c -> this.allCardsIndex.put(c.getId(), c)); this.allCardsIndex.put(object.getId(), (CardView) object);
} else if (object instanceof DungeonView) {
// dungeons
this.allCardsIndex.put(object.getId(), new CardView((DungeonView) object));
} else {
// TODO: enable after all view types added here?
//throw new IllegalArgumentException("Unsupported object type: " + object.getName() + " - " + object.getClass().getSimpleName());
}
});
}); });
} }
@ -808,7 +817,7 @@ public final class GamePanel extends javax.swing.JPanel {
this.gamePane = gamePane; this.gamePane = gamePane;
this.playerId = playerId; this.playerId = playerId;
MageFrame.addGame(gameId, this); MageFrame.addGame(gameId, this);
this.feedbackPanel.init(gameId); this.feedbackPanel.init(gameId, bigCard);
this.feedbackPanel.clear(); this.feedbackPanel.clear();
this.abilityPicker.init(gameId, bigCard); this.abilityPicker.init(gameId, bigCard);
this.btnConcede.setVisible(true); this.btnConcede.setVisible(true);
@ -851,7 +860,7 @@ public final class GamePanel extends javax.swing.JPanel {
this.gamePane = gamePane; this.gamePane = gamePane;
this.playerId = null; this.playerId = null;
MageFrame.addGame(gameId, this); MageFrame.addGame(gameId, this);
this.feedbackPanel.init(gameId); this.feedbackPanel.init(gameId, bigCard);
this.feedbackPanel.clear(); this.feedbackPanel.clear();
this.btnConcede.setVisible(false); this.btnConcede.setVisible(false);
@ -886,7 +895,7 @@ public final class GamePanel extends javax.swing.JPanel {
this.gameId = gameId; this.gameId = gameId;
this.playerId = null; this.playerId = null;
MageFrame.addGame(gameId, this); MageFrame.addGame(gameId, this);
this.feedbackPanel.init(gameId); this.feedbackPanel.init(gameId, bigCard);
this.feedbackPanel.clear(); this.feedbackPanel.clear();
this.btnConcede.setVisible(false); this.btnConcede.setVisible(false);
this.btnSkipToNextTurn.setVisible(false); this.btnSkipToNextTurn.setVisible(false);

View file

@ -1,6 +1,7 @@
package mage.client.game; package mage.client.game;
import mage.client.SessionHandler; import mage.client.SessionHandler;
import mage.client.cards.BigCard;
import mage.client.components.MageTextArea; import mage.client.components.MageTextArea;
import mage.client.constants.Constants; import mage.client.constants.Constants;
import mage.client.dialog.PreferencesDialog; import mage.client.dialog.PreferencesDialog;
@ -89,8 +90,9 @@ public class HelperPanel extends JPanel {
initComponents(); initComponents();
} }
public void init(UUID gameId) { public void init(UUID gameId, BigCard bigCard) {
this.gameId = gameId; this.gameId = gameId;
this.dialogTextArea.setGameData(gameId, bigCard);
} }
public void changeGUISize() { public void changeGUISize() {

View file

@ -878,7 +878,8 @@ public class CardView extends SimpleCardView {
this.displayName = name; this.displayName = name;
this.displayFullName = name; this.displayFullName = name;
this.rules = new ArrayList<>(emblem.getRules()); this.rules = new ArrayList<>(emblem.getRules());
// emblem images are always with common (black) symbol
// image - emblem are always with common (black) symbol
this.frameStyle = FrameStyle.M15_NORMAL; this.frameStyle = FrameStyle.M15_NORMAL;
this.expansionSetCode = emblem.getExpansionSetCode(); this.expansionSetCode = emblem.getExpansionSetCode();
this.cardNumber = emblem.getCardNumber(); this.cardNumber = emblem.getCardNumber();
@ -901,12 +902,13 @@ public class CardView extends SimpleCardView {
this.displayName = name; this.displayName = name;
this.displayFullName = name; this.displayFullName = name;
this.rules = new ArrayList<>(dungeon.getRules()); this.rules = new ArrayList<>(dungeon.getRules());
// emblem images are always with common (black) symbol
this.frameStyle = FrameStyle.M15_NORMAL; // image
this.frameStyle = FrameStyle.M15_NORMAL; // TODO: needs in full art? Test dungeon choose dialog
this.expansionSetCode = dungeon.getExpansionSetCode(); this.expansionSetCode = dungeon.getExpansionSetCode();
this.cardNumber = ""; this.cardNumber = "";
this.imageFileName = ""; this.imageFileName = dungeon.getImageFileName();
this.imageNumber = 0; this.imageNumber = dungeon.getImageNumber();
this.rarity = Rarity.SPECIAL; this.rarity = Rarity.SPECIAL;
this.playableStats = dungeon.playableStats.copy(); this.playableStats = dungeon.playableStats.copy();
@ -923,7 +925,8 @@ public class CardView extends SimpleCardView {
this.displayName = name; this.displayName = name;
this.displayFullName = name; this.displayFullName = name;
this.rules = new ArrayList<>(plane.getRules()); this.rules = new ArrayList<>(plane.getRules());
// Display the plane in landscape (similar to Fused cards)
// image - display the plane in landscape (similar to Fused cards)
this.rotate = true; this.rotate = true;
this.frameStyle = FrameStyle.M15_NORMAL; this.frameStyle = FrameStyle.M15_NORMAL;
this.expansionSetCode = plane.getExpansionSetCode(); this.expansionSetCode = plane.getExpansionSetCode();
@ -947,6 +950,8 @@ public class CardView extends SimpleCardView {
this.displayFullName = name; this.displayFullName = name;
this.rules = new ArrayList<>(); this.rules = new ArrayList<>();
this.rules.add(stackAbility.getRule(designation.getName())); this.rules.add(stackAbility.getRule(designation.getName()));
// image
this.frameStyle = FrameStyle.M15_NORMAL; this.frameStyle = FrameStyle.M15_NORMAL;
this.cardNumber = designation.getCardNumber(); this.cardNumber = designation.getCardNumber();
this.expansionSetCode = designation.getExpansionSetCode(); this.expansionSetCode = designation.getExpansionSetCode();
@ -954,6 +959,7 @@ public class CardView extends SimpleCardView {
this.imageFileName = ""; this.imageFileName = "";
this.imageNumber = 0; this.imageNumber = 0;
this.rarity = Rarity.SPECIAL; this.rarity = Rarity.SPECIAL;
// no playable/chooseable marks for designations // no playable/chooseable marks for designations
} }

View file

@ -584,6 +584,9 @@ public abstract class GameImpl implements Game {
return emblem; return emblem;
} }
TheRingEmblem newEmblem = new TheRingEmblem(playerId); TheRingEmblem newEmblem = new TheRingEmblem(playerId);
// TODO: add image info
state.addCommandObject(newEmblem); state.addCommandObject(newEmblem);
return newEmblem; return newEmblem;
} }
@ -1971,7 +1974,9 @@ public abstract class GameImpl implements Game {
ability.setSourceId(newEmblem.getId()); ability.setSourceId(newEmblem.getId());
} }
state.addCommandObject(newEmblem); // TODO: generate image for emblem here? // image info setup in setSourceObject
state.addCommandObject(newEmblem);
} }
/** /**
@ -1999,6 +2004,9 @@ public abstract class GameImpl implements Game {
for (Ability ability : newPlane.getAbilities()) { for (Ability ability : newPlane.getAbilities()) {
ability.setSourceId(newPlane.getId()); ability.setSourceId(newPlane.getId());
} }
// image info setup in setSourceObject
state.addCommandObject(newPlane); state.addCommandObject(newPlane);
informPlayers("You have planeswalked to " + newPlane.getLogName()); informPlayers("You have planeswalked to " + newPlane.getLogName());
@ -2020,6 +2028,7 @@ public abstract class GameImpl implements Game {
@Override @Override
public Dungeon addDungeon(Dungeon dungeon, UUID playerId) { public Dungeon addDungeon(Dungeon dungeon, UUID playerId) {
dungeon.setControllerId(playerId); dungeon.setControllerId(playerId);
dungeon.setSourceObject();
state.addCommandObject(dungeon); state.addCommandObject(dungeon);
return dungeon; return dungeon;
} }

View file

@ -13,6 +13,8 @@ import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.hint.HintUtils; import mage.abilities.hint.HintUtils;
import mage.cards.FrameStyle; import mage.cards.FrameStyle;
import mage.cards.repository.TokenInfo;
import mage.cards.repository.TokenRepository;
import mage.choices.Choice; import mage.choices.Choice;
import mage.choices.ChoiceHintType; import mage.choices.ChoiceHintType;
import mage.choices.ChoiceImpl; import mage.choices.ChoiceImpl;
@ -87,6 +89,11 @@ public class Dungeon extends CommandObjectImpl {
} }
public void moveToNextRoom(UUID playerId, Game game) { public void moveToNextRoom(UUID playerId, Game game) {
Dungeon dungeon = game.getPlayerDungeon(playerId);
if (dungeon == null) {
return;
}
if (currentRoom == null) { if (currentRoom == null) {
currentRoom = dungeonRooms.get(0); currentRoom = dungeonRooms.get(0);
} else { } else {
@ -94,7 +101,7 @@ public class Dungeon extends CommandObjectImpl {
} }
Player player = game.getPlayer(getControllerId()); Player player = game.getPlayer(getControllerId());
if (player != null) { if (player != null) {
game.informPlayers(player.getLogName() + " has entered " + currentRoom.getName()); game.informPlayers(player.getLogName() + " has entered " + currentRoom.getName() + " (dungeon: " + dungeon.getLogName() + ")");
} }
game.fireEvent(GameEvent.getEvent( game.fireEvent(GameEvent.getEvent(
GameEvent.EventType.ROOM_ENTERED, currentRoom.getId(), null, playerId GameEvent.EventType.ROOM_ENTERED, currentRoom.getId(), null, playerId
@ -139,14 +146,14 @@ public class Dungeon extends CommandObjectImpl {
choice.setChoices(dungeonNames); choice.setChoices(dungeonNames);
player.choose(Outcome.Neutral, choice, game); player.choose(Outcome.Neutral, choice, game);
if (choice.getChoice() != null) { if (choice.getChoice() != null) {
return createDungeon(choice.getChoice()); return createDungeon(choice.getChoice(), true);
} else { } else {
// on disconnect // on disconnect
return createDungeon("Tomb of Annihilation"); return createDungeon("Tomb of Annihilation", true);
} }
} }
public static Dungeon createDungeon(String name) { public static Dungeon createDungeon(String name, boolean isNameMustExists) {
switch (name) { switch (name) {
case "Tomb of Annihilation": case "Tomb of Annihilation":
return new TombOfAnnihilationDungeon(); return new TombOfAnnihilationDungeon();
@ -155,7 +162,26 @@ public class Dungeon extends CommandObjectImpl {
case "Dungeon of the Mad Mage": case "Dungeon of the Mad Mage":
return new DungeonOfTheMadMageDungeon(); return new DungeonOfTheMadMageDungeon();
default: default:
if (isNameMustExists) {
throw new UnsupportedOperationException("A dungeon should have been chosen"); throw new UnsupportedOperationException("A dungeon should have been chosen");
} else {
return null;
}
}
}
public void setSourceObject() {
// choose set code due source
TokenInfo foundInfo = TokenRepository.instance.findPreferredTokenInfoForClass(this.getClass().getName(), null);
if (foundInfo != null) {
this.setExpansionSetCode(foundInfo.getSetCode());
this.setUsesVariousArt(false);
this.setCardNumber("");
this.setImageFileName(""); // use default
this.setImageNumber(foundInfo.getImageNumber());
} else {
// how-to fix: add dungeon to the tokens-database
throw new IllegalArgumentException("Wrong code usage: can't find token info for the dungeon: " + this.getClass().getName());
} }
} }

View file

@ -77,6 +77,11 @@ public class DungeonRoom {
} }
public DungeonRoom chooseNextRoom(UUID playerId, Game game) { public DungeonRoom chooseNextRoom(UUID playerId, Game game) {
Dungeon dungeon = game.getPlayerDungeon(playerId);
if (dungeon == null) {
return null;
}
switch (nextRooms.size()) { switch (nextRooms.size()) {
case 0: case 0:
return null; return null;
@ -90,8 +95,8 @@ public class DungeonRoom {
return null; return null;
} }
return player.chooseUse( return player.chooseUse(
Outcome.Neutral, "Choose which room to go to", Outcome.Neutral, "Choose which room to go to in",
null, room1.name, room2.name, null, game "dungeon: " + dungeon.getLogName(), room1.name, room2.name, null, game
) ? room1 : room2; ) ? room1 : room2;
default: default:
throw new UnsupportedOperationException("there shouldn't be more than two rooms to go to"); throw new UnsupportedOperationException("there shouldn't be more than two rooms to go to");