mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 04:08:01 +00:00
Improve deck editing support for variants
This commit is contained in:
@@ -68,9 +68,9 @@ public final class CEditorConstructed extends ACEditorBase<PaperCard, Deck> {
|
||||
allSections.add(DeckSection.Planes);
|
||||
|
||||
normalPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(), PaperCard.class);
|
||||
avatarPool = ItemPool.createFrom(FModel.getMagicDb().getVariantCards().getAllCards(Predicates.compose(CardRulesPredicates.Presets.IS_VANGUARD, PaperCard.FN_GET_RULES)),PaperCard.class);
|
||||
planePool = ItemPool.createFrom(FModel.getMagicDb().getVariantCards().getAllCards(Predicates.compose(CardRulesPredicates.Presets.IS_PLANE_OR_PHENOMENON, PaperCard.FN_GET_RULES)),PaperCard.class);
|
||||
schemePool = ItemPool.createFrom(FModel.getMagicDb().getVariantCards().getAllCards(Predicates.compose(CardRulesPredicates.Presets.IS_SCHEME, PaperCard.FN_GET_RULES)),PaperCard.class);
|
||||
avatarPool = ItemPool.createFrom(FModel.getMagicDb().getVariantCards().getAllCards(Predicates.compose(CardRulesPredicates.Presets.IS_VANGUARD, PaperCard.FN_GET_RULES)), PaperCard.class);
|
||||
planePool = ItemPool.createFrom(FModel.getMagicDb().getVariantCards().getAllCards(Predicates.compose(CardRulesPredicates.Presets.IS_PLANE_OR_PHENOMENON, PaperCard.FN_GET_RULES)), PaperCard.class);
|
||||
schemePool = ItemPool.createFrom(FModel.getMagicDb().getVariantCards().getAllCards(Predicates.compose(CardRulesPredicates.Presets.IS_SCHEME, PaperCard.FN_GET_RULES)), PaperCard.class);
|
||||
|
||||
CardManager catalogManager = new CardManager(false); // TODO: restore the functionality of the "want uniques only" toggle
|
||||
CardManager deckManager = new CardManager(false); // IMPORTANT: must *always* show all cards in the deck, otherwise cards with different art get ignored!
|
||||
|
||||
@@ -66,17 +66,35 @@ public class FDeckChooser extends FScreen {
|
||||
btnNewDeck.setCommand(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
EditorType editorType;
|
||||
switch (lstDecks.getGameType()) {
|
||||
case Constructed:
|
||||
editorType = EditorType.Constructed;
|
||||
break;
|
||||
case Commander:
|
||||
editorType = EditorType.Commander;
|
||||
break;
|
||||
case Archenemy:
|
||||
editorType = EditorType.Archenemy;
|
||||
break;
|
||||
case Planechase:
|
||||
editorType = EditorType.Planechase;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
FDeckEditor editor;
|
||||
switch (selectedDeckType) {
|
||||
case COLOR_DECK:
|
||||
case THEME_DECK:
|
||||
case RANDOM_DECK:
|
||||
final DeckProxy deck = lstDecks.getSelectedItem();
|
||||
if (deck != null) {
|
||||
Deck generatedDeck = deck.getDeck();
|
||||
if (generatedDeck == null) { return; }
|
||||
|
||||
generatedDeck = (Deck)generatedDeck.copyTo(""); //prevent deck having a name by default
|
||||
editor = new FDeckEditor(EditorType.Constructed, generatedDeck, true);
|
||||
editor = new FDeckEditor(editorType, generatedDeck, true);
|
||||
}
|
||||
else {
|
||||
FOptionPane.showErrorDialog("You must select something before you can generate a new deck.");
|
||||
@@ -84,22 +102,7 @@ public class FDeckChooser extends FScreen {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (lstDecks.getGameType()) {
|
||||
case Constructed:
|
||||
editor = new FDeckEditor(EditorType.Constructed, "", false);
|
||||
break;
|
||||
case Commander:
|
||||
editor = new FDeckEditor(EditorType.Commander, "", false);
|
||||
break;
|
||||
case Archenemy:
|
||||
editor = new FDeckEditor(EditorType.Archenemy, "", false);
|
||||
break;
|
||||
case Planechase:
|
||||
editor = new FDeckEditor(EditorType.Planechase, "", false);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
editor = new FDeckEditor(editorType, "", false);
|
||||
break;
|
||||
}
|
||||
editor.setSaveHandler(new FEventHandler() {
|
||||
@@ -147,7 +150,22 @@ public class FDeckChooser extends FScreen {
|
||||
if (needRefreshOnActivate) {
|
||||
needRefreshOnActivate = false;
|
||||
updateCustom();
|
||||
lstDecks.setSelectedString(DeckPreferences.getCurrentDeck());
|
||||
switch (lstDecks.getGameType()) {
|
||||
case Constructed:
|
||||
lstDecks.setSelectedString(DeckPreferences.getCurrentDeck());
|
||||
break;
|
||||
case Commander:
|
||||
lstDecks.setSelectedString(DeckPreferences.getCommanderDeck());
|
||||
break;
|
||||
case Archenemy:
|
||||
lstDecks.setSelectedString(DeckPreferences.getSchemeDeck());
|
||||
break;
|
||||
case Planechase:
|
||||
lstDecks.setSelectedString(DeckPreferences.getPlanarDeck());
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,16 +196,36 @@ public class FDeckChooser extends FScreen {
|
||||
Deck copiedDeck = (Deck)deck.getDeck().copyTo(deck.getName());
|
||||
decks.add(copiedDeck);
|
||||
setSelectedDeckType(DeckType.CUSTOM_DECK);
|
||||
editDeck(new DeckProxy(copiedDeck, "Constructed", GameType.Constructed, decks));
|
||||
editDeck(new DeckProxy(copiedDeck, "Constructed", lstDecks.getGameType(), decks));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void editDeck(DeckProxy deck) {
|
||||
EditorType editorType;
|
||||
switch (lstDecks.getGameType()) {
|
||||
case Constructed:
|
||||
editorType = EditorType.Constructed;
|
||||
DeckPreferences.setCurrentDeck(deck.getName());
|
||||
break;
|
||||
case Commander:
|
||||
editorType = EditorType.Commander;
|
||||
DeckPreferences.setCommanderDeck(deck.getName());
|
||||
break;
|
||||
case Archenemy:
|
||||
editorType = EditorType.Archenemy;
|
||||
DeckPreferences.setSchemeDeck(deck.getName());
|
||||
break;
|
||||
case Planechase:
|
||||
editorType = EditorType.Planechase;
|
||||
DeckPreferences.setPlanarDeck(deck.getName());
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
needRefreshOnActivate = true;
|
||||
DeckPreferences.setCurrentDeck(deck.getName());
|
||||
Forge.openScreen(new FDeckEditor(EditorType.Constructed, deck, true));
|
||||
Forge.openScreen(new FDeckEditor(editorType, deck, true));
|
||||
}
|
||||
|
||||
public void initialize(FPref savedStateSetting, DeckType defaultDeckType) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
import forge.Forge;
|
||||
@@ -19,6 +20,7 @@ import forge.assets.FSkinFont;
|
||||
import forge.assets.FSkinImage;
|
||||
import forge.assets.FTextureRegionImage;
|
||||
import forge.card.CardEdition;
|
||||
import forge.card.CardRulesPredicates;
|
||||
import forge.card.CardZoom;
|
||||
import forge.deck.io.DeckPreferences;
|
||||
import forge.item.PaperCard;
|
||||
@@ -89,12 +91,6 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
public Deck get() {
|
||||
return new Deck();
|
||||
}
|
||||
})),
|
||||
Vanguard(new DeckController<Deck>(FModel.getDecks().getConstructed(), new Supplier<Deck>() {
|
||||
@Override
|
||||
public Deck get() {
|
||||
return new Deck();
|
||||
}
|
||||
}));
|
||||
|
||||
private final DeckController<? extends DeckBase> controller;
|
||||
@@ -113,7 +109,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
default:
|
||||
case Constructed:
|
||||
return new DeckEditorPage[] {
|
||||
new CatalogPage(),
|
||||
new CatalogPage(ItemManagerConfig.CARD_CATALOG),
|
||||
new DeckSectionPage(DeckSection.Main),
|
||||
new DeckSectionPage(DeckSection.Sideboard)
|
||||
};
|
||||
@@ -130,31 +126,20 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
};
|
||||
case Commander:
|
||||
return new DeckEditorPage[] {
|
||||
new CatalogPage(),
|
||||
new CatalogPage(ItemManagerConfig.CARD_CATALOG),
|
||||
new DeckSectionPage(DeckSection.Main),
|
||||
new DeckSectionPage(DeckSection.Sideboard),
|
||||
new DeckSectionPage(DeckSection.Commander)
|
||||
new DeckSectionPage(DeckSection.Commander, ItemManagerConfig.COMMANDER_SECTION)
|
||||
};
|
||||
case Archenemy:
|
||||
return new DeckEditorPage[] {
|
||||
new CatalogPage(),
|
||||
new DeckSectionPage(DeckSection.Main),
|
||||
new DeckSectionPage(DeckSection.Sideboard),
|
||||
new DeckSectionPage(DeckSection.Schemes)
|
||||
new CatalogPage(ItemManagerConfig.SCHEME_POOL),
|
||||
new DeckSectionPage(DeckSection.Schemes, ItemManagerConfig.SCHEME_DECK_EDITOR)
|
||||
};
|
||||
case Planechase:
|
||||
return new DeckEditorPage[] {
|
||||
new CatalogPage(),
|
||||
new DeckSectionPage(DeckSection.Main),
|
||||
new DeckSectionPage(DeckSection.Sideboard),
|
||||
new DeckSectionPage(DeckSection.Planes)
|
||||
};
|
||||
case Vanguard:
|
||||
return new DeckEditorPage[] {
|
||||
new CatalogPage(),
|
||||
new DeckSectionPage(DeckSection.Main),
|
||||
new DeckSectionPage(DeckSection.Sideboard),
|
||||
new DeckSectionPage(DeckSection.Avatar)
|
||||
new CatalogPage(ItemManagerConfig.PLANAR_POOL),
|
||||
new DeckSectionPage(DeckSection.Planes, ItemManagerConfig.PLANAR_DECK_EDITOR)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -193,11 +178,17 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
}
|
||||
else if (tabPage instanceof DeckSectionPage) {
|
||||
DeckSectionPage deckSectionPage = (DeckSectionPage) tabPage;
|
||||
if (deckSectionPage.deckSection == DeckSection.Main) {
|
||||
switch (deckSectionPage.deckSection) {
|
||||
case Main:
|
||||
case Schemes:
|
||||
case Planes:
|
||||
mainDeckPage = deckSectionPage;
|
||||
}
|
||||
else if (deckSectionPage.deckSection == DeckSection.Sideboard) {
|
||||
break;
|
||||
case Sideboard:
|
||||
sideboardPage = deckSectionPage;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -364,7 +355,6 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
switch (editorType) {
|
||||
case Constructed:
|
||||
case Planechase:
|
||||
case Vanguard:
|
||||
case Archenemy:
|
||||
default:
|
||||
if (FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY)) {
|
||||
@@ -576,6 +566,12 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
if (deck.has(DeckSection.Commander)) {
|
||||
max -= deck.get(DeckSection.Commander).count(card);
|
||||
}
|
||||
if (deck.has(DeckSection.Planes)) {
|
||||
max -= deck.get(DeckSection.Planes).count(card);
|
||||
}
|
||||
if (deck.has(DeckSection.Schemes)) {
|
||||
max -= deck.get(DeckSection.Schemes).count(card);
|
||||
}
|
||||
}
|
||||
if (isAddSource) {
|
||||
if (qty > max) {
|
||||
@@ -640,11 +636,16 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
protected static class CatalogPage extends CardManagerPage {
|
||||
private boolean initialized, needRefreshWhenShown;
|
||||
|
||||
protected CatalogPage() {
|
||||
this(ItemManagerConfig.CARD_CATALOG, "Catalog", FSkinImage.FOLDER);
|
||||
protected CatalogPage(ItemManagerConfig config) {
|
||||
this(config, "Catalog", FSkinImage.FOLDER);
|
||||
}
|
||||
protected CatalogPage(ItemManagerConfig config, String caption0, FImage icon0) {
|
||||
super(config, caption0, icon0);
|
||||
|
||||
if (config == ItemManagerConfig.PLANAR_POOL || config == ItemManagerConfig.SCHEME_POOL) {
|
||||
//prevent showing image view options for planar and scheme pools by default
|
||||
cardManager.setHideViewOptions(1, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -662,7 +663,14 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
}
|
||||
|
||||
protected String getItemManagerCaption() {
|
||||
return "Cards";
|
||||
switch (parentScreen.getEditorType()) {
|
||||
case Archenemy:
|
||||
return "Schemes";
|
||||
case Planechase:
|
||||
return "Planes";
|
||||
default:
|
||||
return "Cards";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -681,7 +689,17 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
needRefreshWhenShown = true;
|
||||
return; //delay refreshing while hidden
|
||||
}
|
||||
cardManager.setPool(ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(), PaperCard.class), true);
|
||||
switch (parentScreen.getEditorType()) {
|
||||
case Archenemy:
|
||||
cardManager.setPool(ItemPool.createFrom(FModel.getMagicDb().getVariantCards().getAllCards(Predicates.compose(CardRulesPredicates.Presets.IS_SCHEME, PaperCard.FN_GET_RULES)), PaperCard.class), true);
|
||||
break;
|
||||
case Planechase:
|
||||
cardManager.setPool(ItemPool.createFrom(FModel.getMagicDb().getVariantCards().getAllCards(Predicates.compose(CardRulesPredicates.Presets.IS_PLANE_OR_PHENOMENON, PaperCard.FN_GET_RULES)), PaperCard.class), true);
|
||||
break;
|
||||
default:
|
||||
cardManager.setPool(ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(), PaperCard.class), true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -691,7 +709,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
|
||||
@Override
|
||||
protected void buildMenu(final FDropDownMenu menu, final PaperCard card) {
|
||||
addItem(menu, "Add", "to main deck", parentScreen.getMainDeckPage().getIcon(), true, true, new Callback<Integer>() {
|
||||
addItem(menu, "Add", "to " + parentScreen.getMainDeckPage().cardManager.getCaption().toLowerCase(), parentScreen.getMainDeckPage().getIcon(), true, true, new Callback<Integer>() {
|
||||
@Override
|
||||
public void run(Integer result) {
|
||||
if (result == null || result <= 0) { return; }
|
||||
@@ -699,14 +717,16 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
parentScreen.getMainDeckPage().addCard(card, result);
|
||||
}
|
||||
});
|
||||
addItem(menu, "Add", "to sideboard", parentScreen.getSideboardPage().getIcon(), true, true, new Callback<Integer>() {
|
||||
@Override
|
||||
public void run(Integer result) {
|
||||
if (result == null || result <= 0) { return; }
|
||||
|
||||
parentScreen.getSideboardPage().addCard(card, result);
|
||||
}
|
||||
});
|
||||
if (parentScreen.getSideboardPage() != null) {
|
||||
addItem(menu, "Add", "to sideboard", parentScreen.getSideboardPage().getIcon(), true, true, new Callback<Integer>() {
|
||||
@Override
|
||||
public void run(Integer result) {
|
||||
if (result == null || result <= 0) { return; }
|
||||
|
||||
parentScreen.getSideboardPage().addCard(card, result);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -737,21 +757,25 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
captionPrefix = "Commander";
|
||||
cardManager.setCaption("Commander");
|
||||
icon = FSkinImage.PLANESWALKER;
|
||||
cardManager.setHideViewOptions(1, true); //image view options not needed
|
||||
break;
|
||||
case Avatar:
|
||||
captionPrefix = "Avatar";
|
||||
cardManager.setCaption("Avatar");
|
||||
icon = new FTextureRegionImage(FSkin.getAvatars().get(0));
|
||||
cardManager.setHideViewOptions(1, true); //image view options not needed
|
||||
break;
|
||||
case Planes:
|
||||
captionPrefix = "Planes";
|
||||
cardManager.setCaption("Planes");
|
||||
icon = FSkinImage.CHAOS;
|
||||
cardManager.setHideViewOptions(1, true); //image view options not needed
|
||||
break;
|
||||
case Schemes:
|
||||
captionPrefix = "Schemes";
|
||||
cardManager.setCaption("Schemes");
|
||||
icon = FSkinImage.POISON;
|
||||
cardManager.setHideViewOptions(1, true); //image view options not needed
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -771,6 +795,8 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
protected void onCardActivated(PaperCard card) {
|
||||
switch (deckSection) {
|
||||
case Main:
|
||||
case Planes:
|
||||
case Schemes:
|
||||
removeCard(card);
|
||||
switch (parentScreen.getEditorType()) {
|
||||
case Draft:
|
||||
|
||||
@@ -21,7 +21,7 @@ import org.w3c.dom.NodeList;
|
||||
*
|
||||
*/
|
||||
public class DeckPreferences {
|
||||
private static String currentDeck, draftDeck, sealedDeck;
|
||||
private static String currentDeck, draftDeck, sealedDeck, commanderDeck, planarDeck, schemeDeck;
|
||||
private static Map<String, DeckPreferences> allPrefs = new HashMap<String, DeckPreferences>();
|
||||
|
||||
public static String getCurrentDeck() {
|
||||
@@ -51,6 +51,33 @@ public class DeckPreferences {
|
||||
save();
|
||||
}
|
||||
|
||||
public static String getCommanderDeck() {
|
||||
return commanderDeck;
|
||||
}
|
||||
public static void setCommanderDeck(String commanderDeck0) {
|
||||
if (commanderDeck != null && commanderDeck.equals(commanderDeck0)) { return; }
|
||||
commanderDeck = commanderDeck0;
|
||||
save();
|
||||
}
|
||||
|
||||
public static String getPlanarDeck() {
|
||||
return planarDeck;
|
||||
}
|
||||
public static void setPlanarDeck(String planarDeck0) {
|
||||
if (planarDeck != null && planarDeck.equals(planarDeck0)) { return; }
|
||||
planarDeck = planarDeck0;
|
||||
save();
|
||||
}
|
||||
|
||||
public static String getSchemeDeck() {
|
||||
return schemeDeck;
|
||||
}
|
||||
public static void setSchemeDeck(String schemeDeck0) {
|
||||
if (schemeDeck != null && schemeDeck.equals(schemeDeck0)) { return; }
|
||||
schemeDeck = schemeDeck0;
|
||||
save();
|
||||
}
|
||||
|
||||
public static DeckPreferences getPrefs(DeckProxy deck) {
|
||||
String key = deck.getUniqueKey();
|
||||
DeckPreferences prefs = allPrefs.get(key);
|
||||
@@ -72,6 +99,9 @@ public class DeckPreferences {
|
||||
currentDeck = root.getAttribute("currentDeck");
|
||||
draftDeck = root.getAttribute("draftDeck");
|
||||
sealedDeck = root.getAttribute("sealedDeck");
|
||||
commanderDeck = root.getAttribute("commanderDeck");
|
||||
planarDeck = root.getAttribute("planarDeck");
|
||||
schemeDeck = root.getAttribute("schemeDeck");
|
||||
|
||||
final NodeList cards = document.getElementsByTagName("deck");
|
||||
for (int i = 0; i < cards.getLength(); i++) {
|
||||
@@ -101,6 +131,9 @@ public class DeckPreferences {
|
||||
root.setAttribute("currentDeck", currentDeck);
|
||||
root.setAttribute("draftDeck", draftDeck);
|
||||
root.setAttribute("sealedDeck", sealedDeck);
|
||||
root.setAttribute("commanderDeck", commanderDeck);
|
||||
root.setAttribute("planarDeck", planarDeck);
|
||||
root.setAttribute("schemeDeck", schemeDeck);
|
||||
document.appendChild(root);
|
||||
|
||||
for (Map.Entry<String, DeckPreferences> entry : allPrefs.entrySet()) {
|
||||
|
||||
@@ -42,12 +42,18 @@ public enum ItemManagerConfig {
|
||||
GroupDef.DEFAULT, ColumnDef.CMC, 4, 1),
|
||||
AVATAR_POOL(SColumnUtil.getSpecialCardPoolDefaultColumns(), true, false, false,
|
||||
null, null, 4, 0),
|
||||
SCHEME_POOL(SColumnUtil.getSpecialCardPoolDefaultColumns(), true, false, false,
|
||||
SCHEME_POOL(SColumnUtil.getSpecialCardPoolDefaultColumns(), true, false, true,
|
||||
null, null, 4, 0),
|
||||
PLANAR_POOL(SColumnUtil.getSpecialCardPoolDefaultColumns(), true, false, false,
|
||||
SCHEME_DECK_EDITOR(SColumnUtil.getCatalogDefaultColumns(true), true, false, true,
|
||||
null, null, 4, 0),
|
||||
PLANAR_POOL(SColumnUtil.getSpecialCardPoolDefaultColumns(), true, false, true,
|
||||
null, null, 4, 0),
|
||||
PLANAR_DECK_EDITOR(SColumnUtil.getCatalogDefaultColumns(true), true, false, true,
|
||||
null, null, 4, 0),
|
||||
COMMANDER_POOL(SColumnUtil.getCatalogDefaultColumns(true), true, false, false,
|
||||
null, null, 4, 0),
|
||||
COMMANDER_SECTION(SColumnUtil.getCatalogDefaultColumns(true), true, false, true,
|
||||
null, null, 1, 1),
|
||||
WORKSHOP_CATALOG(SColumnUtil.getCatalogDefaultColumns(true), true, true, false,
|
||||
null, null, 4, 0),
|
||||
DECK_VIEWER(SColumnUtil.getDeckViewerDefaultColumns(), false, false, false,
|
||||
|
||||
Reference in New Issue
Block a user