Add alternative keywords view; images disabled.

master
lodici 2016-10-14 20:16:52 +01:00
parent 56bad00555
commit 054ddcddad
12 changed files with 347 additions and 61 deletions

View File

@ -1,74 +1,125 @@
#
# Magarena keywords glossary.
#
# A blank like will be ignored.
# A line starting with...
# '#' will be ignored.
# '*' is the keyword definition.
# '@' is a list of card names (semi-colon delimiter) demonstrating the keyword.
# none of the above is assumed to be the keyword description.
#
*Absorb N
If a source would deal damage to this creature, prevent N of that damage.
@Lymph Sliver
*Affinity for [...]
This spell costs you {1} less to cast for each [...] you control.
@Frogmite;Razor Golem
*Amplify N
As this object enters the battlefield, reveal any number of cards from your hand that share a creature type with it. This permanent enters the battlefield with N +1/+1 counters on it for each card revealed this way. You can't reveal this card or any other cards that are entering the battlefield at the same time as this card.
@Kilnmouth Dragon
*Annihilator N
Whenever this creature attacks, defending player sacrifices N permanents.
@Artisan of Kozilek;Ulamog, the Infinite Gyre;Eldrazi Conscription
*Aura Swap [cost]
[cost]: You may exchange this permanent with an Aura card in your hand.
@Arcanum Wings
*Awaken N—[cost]
You may pay [cost] rather than pay this spell's mana cost as you cast this spell.
If this spell's awaken cost was paid, put N +1/+1 counters on target land you control. That land becomes a 0/0 Elemental creature with haste. It's still a land.
@Earthen Arms
*Banding
Any creatures with banding, and up to one without, can attack in a band. Bands are blocked as a group. If any creatures with banding you control are blocking or being blocked by a creature, you divide that creature's combat damage, not its controller, among any of the creatures it's being blocked by or is blocking.
@Timber Wolves
*Bands with other [...]
Any creatures named [...] can attack in a band as long as at least one has "bands with other [...]" Bands are blocked as a group. If at least two creatures named [...] you control, one of which has "bands with other [...]," are blocking or being blocked by the same creature, you divide that creature's combat damage, not its controller, among any of the creatures it's being blocked by or is blocking.
@Adventurers' Guildhouse
*Battle Cry
Whenever this creature attacks, each other attacking creature gets +1/+0 until end of turn.
*Bestow [cost]
You may cast this card by paying [cost] rather than its mana cost.
If you chose to pay this spells bestow cost, it becomes an Aura enchantment and gains enchant creature. These effects last until one of two things happens: this spell has an illegal target as it resolves or the permanent this spell becomes, becomes unattached.
*Bloodthirst N
If an opponent was dealt damage this turn, this permanent enters the battlefield with N +1/+1 counters on it.
*Bloodthirst X
This permanent enters the battlefield with X +1/+1 counters on it, where X is the total damage your opponents have been dealt this turn.
*Bushido N
Whenever this creature blocks or becomes blocked, it gets +N/+N until end of turn.
*Buyback [cost]
You may pay an additional [cost] as you cast this spell.
If the buyback cost was paid, put this spell into its owners hand instead of into that players graveyard as it resolves.
*Cascade
When you cast this spell, exile cards from the top of your library until you exile a nonland card whose converted mana cost is less than this spells converted mana cost. You may cast that card without paying its mana cost. Then put all cards exiled this way that werent cast on the bottom of your library in a random order.
*Champion an [...]
When this permanent enters the battlefield, sacrifice it unless you exile another [...] you control.
When this permanent leaves the battlefield, return the exiled card to the battlefield under its owners control.
*Changeling
This object is every creature type at all times.
*Cipher
Then you may exile this spell card encoded on a creature you control. Whenever that creature deals combat damage to a player, its controller may cast a copy of this card without paying its mana cost.
*Conspire
As an additional cost to cast this spell, you may tap two untapped creatures you control that each share a color with it.
When you cast this spell, if its conspire cost was paid, copy it. If the spell has any targets, you may choose new targets for the copy.
*Convoke
For each colored mana in this spells total cost, you may tap an untapped creature of that color you control rather than pay that mana. For each generic mana in this spells total cost, you may tap an untapped creature you control rather than pay that mana.
*Crew N
Tap any number of creatures you control with total power N or more: This vehicle becomes an artifact creature until end of turn.
*Cumulative Upkeep [cost]
At the beginning of your upkeep, if this permanent is on the battlefield, put an age counter on this permanent. Then you may pay [cost] for each age counter on it. If you dont, sacrifice it.
*Cycling [cost]
[cost], Discard this card: Draw a card.
*Dash [cost]
You may cast this card by paying [cost] rather that its mana cost.
If this spells dash cost was paid, return the permanent this spell becomes to its owners hand at the beginning of the next end step.
As long as this permanents dash cost was paid, it has haste.
*Deathtouch
Any amount of damage this deals to a creature is enough to destroy it.
*Defender
This creature can't attack.
*Delve
For each generic mana in this spells total cost, you may exile a card from your graveyard rather than pay that mana.
*Dethrone
Whenever this creature attacks the player with the most life or tied for most life, put a +1/+1 counter on this creature.
*Devoid
This object is colorless.
*Devour N
As this object enters the battlefield, you may sacrifice any number of creatures. This permanent enters the battlefield with N +1/+1 counters on it for each creature sacrificed this way.
*Double Strike
This creature deals both first-strike and regular combat damage.
*Dredge N
As long as you have at least N cards in your library, if you would draw a card, you may instead put N cards from the top of your library into your graveyard and return this card from your graveyard to your hand.
*Echo [cost]
At the beginning of your upkeep, if this permanent came under your control since the beginning of your last upkeep, sacrifice it unless you pay [cost].
*Emerge [cost]
@ -128,8 +179,11 @@ This permanent enters the battlefield with N +1/+1 counters on it.
Whenever another creature enters the battlefield, if this permanent has a +1/+1 counter on it, you may move a +1/+1 counter from this permanent onto that creature.
*Gravestorm
When you cast this spell, put a copy of it onto the stack for each permanent that was put into a graveyard from battlefield this turn. If the spell has any targets, you may choose new targets for any of the copies.
*Haste
This creature can attack and {T} as soon as it comes under your control.
@Ankle Shanker;Lightning Elemental
*Haunt
When this creature dies, exile it haunting target creature.
*Hexproof

View File

@ -1,40 +0,0 @@
package magic.data;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import magic.utility.MagicResources;
public class KeywordDefinitions {
private KeywordDefinitions() {
}
public static List<KeywordDefinition> getKeywordDefinitions() {
final List<KeywordDefinition> keywordDefinitions = new ArrayList<>();
final String content = MagicResources.getKeywordsFileContent();
KeywordDefinition current = null;
try (final Scanner sc = new Scanner(content)) {
while (sc.hasNextLine()) {
final String line = sc.nextLine();
if (line.startsWith("*")) {
current = new KeywordDefinition();
current.name = line.substring(1).trim();
keywordDefinitions.add(current);
} else {
if (current.description.length() > 0) {
current.description = current.description + "<br>" + line.trim();
} else {
current.description = line.trim();
}
}
}
}
return keywordDefinitions;
}
public static class KeywordDefinition {
public String name;
public String description = "";
}
}

View File

@ -0,0 +1,34 @@
package magic.ui.screen.keywords;
import java.awt.Color;
import magic.data.CardDefinitions;
import magic.ui.theme.Theme;
import magic.ui.utility.MagicStyle;
import magic.ui.widget.TexturedPanel;
import net.miginfocom.swing.MigLayout;
@SuppressWarnings("serial")
class ContentPanelB extends TexturedPanel {
ContentPanelB() {
// TODO
// This is requird to show images of missing cards but is not desirable
// due the lengthy load time of missing scripts. It would be much more
// efficient in this particular case to check for the image directly
// since we already have the card name.
CardDefinitions.getMissingCards();
KeywordPanelB keywordPanel = new KeywordPanelB();
setLayout(new MigLayout("", "[grow, fill][500!, grow, fill]", "[grow, fill]"));
add(new KeywordsListPane(keywordPanel));
add(keywordPanel);
// setBackground(ActionBar.getBackgroundColor().darker());
final Color refBG = MagicStyle.getTheme().getColor(Theme.COLOR_TITLE_BACKGROUND);
final Color thisBG = MagicStyle.getTranslucentColor(refBG, 220);
setBackground(thisBG.darker());
}
}

View File

@ -0,0 +1,57 @@
package magic.ui.screen.keywords;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import magic.data.CardDefinitions;
import magic.model.MagicCardDefinition;
class Keyword implements Comparable<Keyword> {
private final String name;
private final List<String> description = new ArrayList<>();
private String[] cards = new String[]{};
Keyword(String name) {
this.name = name;
}
@Override
public int compareTo(Keyword o) {
return name.compareTo(o.name);
}
void setExampleCards(String[] cards) {
this.cards = cards;
}
List<MagicCardDefinition> getExampleCards() {
try {
return Stream.of(cards)
.map(c -> CardDefinitions.getMissingOrCard(c))
.collect(Collectors.toList());
} catch (Exception ex) {
System.err.println(ex);
return new ArrayList<>();
}
}
@Override
public String toString() {
return name;
}
void addDescriptionLine(String line) {
description.add(line);
}
String getName() {
return name;
}
String getDescriptionAsHtml() {
return description.stream()
.collect(Collectors.joining("<br><br>", "<html>", "</html>"));
}
}

View File

@ -3,30 +3,29 @@ package magic.ui.screen.keywords;
import java.awt.Color;
import javax.swing.JLabel;
import javax.swing.JPanel;
import magic.data.KeywordDefinitions.KeywordDefinition;
import magic.ui.theme.Theme;
import magic.ui.utility.MagicStyle;
import magic.ui.FontsAndBorders;
import net.miginfocom.swing.MigLayout;
@SuppressWarnings("serial")
class KeywordPanel extends JPanel {
class KeywordPanelA extends JPanel {
private static final Color NAME_COLOR = MagicStyle.getTheme().getColor(Theme.COLOR_NAME_FOREGROUND);
private static final Color TEXT_COLOR = MagicStyle.getTheme().getTextColor();
KeywordPanel(KeywordDefinition keyword) {
KeywordPanelA(Keyword keyword) {
setLayout(new MigLayout("insets 0, gap 0, flowy"));
setOpaque(false);
final JLabel nameLabel = new JLabel(keyword.name);
final JLabel nameLabel = new JLabel(keyword.getName());
nameLabel.setForeground(NAME_COLOR);
nameLabel.setFont(FontsAndBorders.FONT2);
add(nameLabel, "w 100%");
final JLabel descriptionLabel = new JLabel();
descriptionLabel.setText("<html>" + keyword.description.replace("<br>", " ") + "</html>");
descriptionLabel.setText(keyword.getDescriptionAsHtml());
descriptionLabel.setForeground(TEXT_COLOR);
add(descriptionLabel, "w 10:100%");
}

View File

@ -0,0 +1,78 @@
package magic.ui.screen.keywords;
import java.awt.Color;
import java.awt.Font;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import magic.awt.MagicFont;
import magic.model.MagicCardDefinition;
import magic.ui.widget.cards.canvas.CardsCanvas;
import net.miginfocom.swing.MigLayout;
@SuppressWarnings("serial")
class KeywordPanelB extends JPanel {
private static final Font KEYWORD_FONT =
MagicFont.MPlantinBold.get().deriveFont(24f);
private static final Font TEXT_FONT =
MagicFont.MPlantin.get().deriveFont(21f);
private final JLabel keywordLabel = new JLabel();
private final JLabel textLabel = new JLabel();
private final CardsCanvas cardsCanvas = new CardsCanvas();
KeywordPanelB() {
cardsCanvas.setAnimationEnabled(false);
cardsCanvas.setLayoutMode(CardsCanvas.LayoutMode.SCALE_TO_FIT);
keywordLabel.setForeground(Color.WHITE);
keywordLabel.setFont(KEYWORD_FONT);
textLabel.setForeground(Color.WHITE);
textLabel.setFont(TEXT_FONT);
textLabel.setVerticalAlignment(SwingConstants.TOP);
setLayout(new MigLayout("flowy, insets n 30 n n",
"[fill, grow]",
"[40!][growprio 200][bottom, grow, fill]")
);
refreshLayout();
setBorder(BorderFactory.createMatteBorder(0, 1, 0, 0, Color.GRAY));
setOpaque(false);
}
private void drawCardImages(Keyword keyword) {
showExampleCard(keyword);
}
private void refreshLayout() {
removeAll();
add(keywordLabel);
add(textLabel);
add(cardsCanvas, "h ::560");
revalidate();
}
private void showExampleCard(Keyword keyword) {
final List<MagicCardDefinition> cards = keyword.getExampleCards();
if (!cards.isEmpty()) {
// cardsCanvas.setCard(cards.get(MagicRandom.nextRNGInt(cards.size())));
} else {
// cardsCanvas.clear();
}
}
void setKeyword(Keyword keyword) {
keywordLabel.setText(keyword.getName());
textLabel.setText(keyword.getDescriptionAsHtml());
drawCardImages(keyword);
refreshLayout();
}
}

View File

@ -0,0 +1,47 @@
package magic.ui.screen.keywords;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import magic.utility.MagicResources;
final class KeywordsHelper {
private KeywordsHelper() { }
static Keyword[] loadKeywordsFileToSortedArray() {
final List<Keyword> keywords = new ArrayList<>();
final String content = MagicResources.getKeywordsFileContent();
Keyword keyword = null;
try (final Scanner sc = new Scanner(content)) {
while (sc.hasNextLine()) {
final String line = sc.nextLine().trim();
if (line.isEmpty() || line.startsWith("#")) {
// ignore a comment or blank line.
} else if (line.startsWith("*")) {
// start of a new keyword definition
keyword = new Keyword(line.substring(1));
keywords.add(keyword);
} else if (line.startsWith("@")) {
// one or more card names
keyword.setExampleCards(line.substring(1).split(";"));
} else {
// one or more lines with keyword description
keyword.addDescriptionLine(line);
}
}
}
return keywords.stream()
.sorted()
.toArray(sz -> new Keyword[sz]);
}
}

View File

@ -0,0 +1,30 @@
package magic.ui.screen.keywords;
import java.awt.Color;
import java.awt.Component;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JList;
import magic.ui.utility.MagicStyle;
@SuppressWarnings("serial")
class KeywordsListCellRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
/* The DefaultListCellRenderer class will take care of
* the JLabels text property, it's foreground and background
* colors, and so on.
*/
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
setForeground(isSelected
? MagicStyle.getRolloverColor()
: Color.LIGHT_GRAY);
setOpaque(false);
return this;
}
}

View File

@ -0,0 +1,35 @@
package magic.ui.screen.keywords;
import java.awt.Color;
import javax.swing.JList;
import javax.swing.JScrollPane;
@SuppressWarnings("serial")
class KeywordsListPane extends JScrollPane {
KeywordsListPane(final KeywordPanelB keywordPanel) {
JList<Keyword> list = new JList<>(KeywordsHelper.loadKeywordsFileToSortedArray());
list.setLayoutOrientation(JList.VERTICAL_WRAP);
list.setVisibleRowCount(-1);
list.setOpaque(false);
list.setCellRenderer(new KeywordsListCellRenderer());
list.setForeground(Color.WHITE);
list.setFont(list.getFont().deriveFont(14f));
list.addListSelectionListener((e) -> {
final Keyword keyword = list.getSelectedValue();
keywordPanel.setKeyword(keyword);
});
list.setSelectedIndex(0);
setViewportView(list);
setOpaque(false);
getViewport().setOpaque(false);
}
}

View File

@ -27,9 +27,9 @@ public class KeywordsScreen extends HeaderFooterScreen {
}
private void setContent() {
setMainContent(ScreenLayout.getLayout() == ScreenLayout.Layout1
setMainContent(ScreenLayout.getLayout() == ScreenLayout.Layout_A
? new ContentPanelA()
: new ContentPanelA()
: new ContentPanelB()
);
clearFooterButtons();
addToFooter(MenuButton.buildLayoutButton(this::doChangeLayout));

View File

@ -4,8 +4,6 @@ import java.awt.Dimension;
import java.awt.Rectangle;
import javax.swing.JPanel;
import javax.swing.Scrollable;
import magic.data.KeywordDefinitions;
import magic.data.KeywordDefinitions.KeywordDefinition;
import net.miginfocom.swing.MigLayout;
/**
@ -24,8 +22,8 @@ class KeywordsScrollablePanel extends JPanel implements Scrollable {
}
private void refreshKeywords() {
for (final KeywordDefinition keywordDefinition : KeywordDefinitions.getKeywordDefinitions()) {
add(new KeywordPanel(keywordDefinition), "w 10:100%, top");
for (final Keyword keywordDefinition : KeywordsHelper.loadKeywordsFileToSortedArray()) {
add(new KeywordPanelA(keywordDefinition), "w 10:100%, top");
}
}

View File

@ -7,28 +7,22 @@ enum ScreenLayout {
/**
* Original two column text only on light background.
*/
Layout1,
Layout_A,
/**
* Multi-column list of keywords on dark translucent background.
* Can show sample card image for selected keyword.
*/
Layout2A,
/**
* Multi-column list of keywords on dark translucent background.
* Can multiple sample card thumbnail images for selected keyword.
*/
Layout2B;
Layout_B;
private static ScreenLayout layout;
static {
try {
final String setting = GeneralConfig.getInstance().getKeywordsSettings();
layout = setting.isEmpty() ? Layout1 : valueOf(setting);
layout = setting.isEmpty() ? Layout_A : valueOf(setting);
} catch (Exception ex) {
System.err.println(ex);
layout = Layout1;
layout = Layout_A;
}
}