From 5bbcf03cb6d6207c2c7c34fae4fce1ac733291fb Mon Sep 17 00:00:00 2001
From: spjspj <spjspj@github.com>
Date: Sat, 11 Sep 2021 23:32:34 +1000
Subject: [PATCH] EDH Power level update (based on Saltiest EDHREC survey). 
 Update for Full Art Face art.

---
 .../CardViewEDHPowerLevelComparator.java      | 323 +++++++++++-------
 .../org/mage/card/arcane/CardRenderer.java    |  24 +-
 .../mage/card/arcane/ModernCardRenderer.java  |  36 +-
 .../src/mage/deck/Commander.java              | 218 ++++++++++--
 4 files changed, 433 insertions(+), 168 deletions(-)

diff --git a/Mage.Client/src/main/java/mage/client/util/comparators/CardViewEDHPowerLevelComparator.java b/Mage.Client/src/main/java/mage/client/util/comparators/CardViewEDHPowerLevelComparator.java
index 34105d8f14..06609df4ca 100644
--- a/Mage.Client/src/main/java/mage/client/util/comparators/CardViewEDHPowerLevelComparator.java
+++ b/Mage.Client/src/main/java/mage/client/util/comparators/CardViewEDHPowerLevelComparator.java
@@ -315,203 +315,280 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
         }
 
         if (card.isPlanesWalker()) {
-            if (card.getName().toLowerCase(Locale.ENGLISH).equals("jace, the mind sculptor")) {
-                thisMaxPower = Math.max(thisMaxPower, 6);
-            }
-            if (card.getName().toLowerCase(Locale.ENGLISH).equals("ugin, the spirit dragon")) {
-                thisMaxPower = Math.max(thisMaxPower, 5);
-            }
-            thisMaxPower = Math.max(thisMaxPower, 4);
+            thisMaxPower = Math.max(thisMaxPower, 6);
         }
 
         String cn = card.getName().toLowerCase(Locale.ENGLISH);
-        if (cn.equals("ancient tomb")
+        if (cn.equals("acid rain")
+                || cn.equals("agent of treachery")
                 || cn.equals("anafenza, the foremost")
+                || cn.equals("ancient tomb")
+                || cn.equals("animar, soul of element")
+                || cn.equals("animate artifact")
+                || cn.equals("apocalypse")
+                || cn.equals("archaeomancer")
                 || cn.equals("arcum dagsson")
                 || cn.equals("armageddon")
+                || cn.equals("ashnod's altar")
+                || cn.equals("atraxa, praetors' voice")
+                || cn.equals("aura flux")
                 || cn.equals("aura shards")
+                || cn.equals("avacyn, angel of hope")
                 || cn.equals("azami, lady of scrolls")
                 || cn.equals("azusa, lost but seeking")
                 || cn.equals("back to basics")
                 || cn.equals("bane of progress")
                 || cn.equals("basalt monolith")
+                || cn.equals("bend or break")
                 || cn.equals("blightsteel collossus")
+                || cn.equals("blightsteel colossus")
                 || cn.equals("blood moon")
+                || cn.equals("boil")
+                || cn.equals("boiling seas")
+                || cn.equals("brago, king eternal")
                 || cn.equals("braids, cabal minion")
+                || cn.equals("bribery")
+                || cn.equals("burning sands")
                 || cn.equals("cabal coffers")
+                || cn.equals("candelabra of tawnos")
                 || cn.equals("captain sisay")
+                || cn.equals("card view")
+                || cn.equals("cataclysm")
+                || cn.equals("catastrophe")
                 || cn.equals("celestial dawn")
+                || cn.equals("cephalid aristocrat")
+                || cn.equals("cephalid illusionist")
+                || cn.equals("changeling berserker")
                 || cn.equals("child of alara")
+                || cn.equals("chulane, teller of tales")
+                || cn.equals("cinderhaze wretch")
                 || cn.equals("coalition relic")
+                || cn.equals("confusion in the ranks")
+                || cn.equals("consecrated sphinx")
+                || cn.equals("contamination")
                 || cn.equals("craterhoof behemoth")
+                || cn.equals("cryptic gateway")
+                || cn.equals("cyclonic rift")
+                || cn.equals("deadeye navigator")
+                || cn.equals("death cloud")
+                || cn.equals("decree of annihilation")
+                || cn.equals("decree of silence")
                 || cn.equals("deepglow skate")
+                || cn.equals("demonic consultation")
                 || cn.equals("derevi, empyrial tactician")
+                || cn.equals("devastation")
                 || cn.equals("dig through time")
+                || cn.equals("divine intervention")
+                || cn.equals("dockside extortionist")
+                || cn.equals("doomsday")
+                || cn.equals("doubling season")
+                || cn.equals("drannith magistrate")
+                || cn.equals("dross scorpion")
+                || cn.equals("earthcraft")
                 || cn.equals("edric, spymaster of trest")
                 || cn.equals("elesh norn, grand cenobite")
+                || cn.equals("embargo")
+                || cn.equals("emrakul, the promised end")
+                || cn.equals("enter the infinite")
                 || cn.equals("entomb")
-                || cn.equals("force of will")
+                || cn.equals("epicenter")
+                || cn.equals("erratic portal")
+                || cn.equals("expropriate")
+                || cn.equals("exquisite blood")
+                || cn.equals("fall of the thran")
+                || cn.equals("fierce guardianship")
                 || cn.equals("food chain")
+                || cn.equals("force of negation")
+                || cn.equals("force of will")
+                || cn.equals("future sight")
                 || cn.equals("gaddock teeg")
                 || cn.equals("gaea's cradle")
+                || cn.equals("genesis chamber")
+                || cn.equals("ghave, guru of spores")
+                || cn.equals("gilded drake")
+                || cn.equals("glenn, the voice of calm")
+                || cn.equals("global ruin")
+                || cn.equals("golos, tireless pilgrim")
                 || cn.equals("grand arbiter augustin iv")
+                || cn.equals("grave pact")
+                || cn.equals("grave titan")
+                || cn.equals("great whale")
                 || cn.equals("grim monolith")
+                || cn.equals("grip of chaos")
+                || cn.equals("gush")
+                || cn.equals("hellkite charger")
                 || cn.equals("hermit druid")
                 || cn.equals("hokori, dust drinker")
                 || cn.equals("humility")
+                || cn.equals("impending disaster")
                 || cn.equals("imperial seal")
+                || cn.equals("intruder alarm")
+                || cn.equals("invoke prejudice")
                 || cn.equals("iona, shield of emeria")
                 || cn.equals("jin-gitaxias, core augur")
+                || cn.equals("jokulhaups")
+                || cn.equals("kaalia of the vast")
                 || cn.equals("karador, ghost chieftain")
                 || cn.equals("karakas")
+                || cn.equals("karn, silver golem")
                 || cn.equals("kataki, war's wage")
+                || cn.equals("keldon firebombers")
+                || cn.equals("kiki-jiki, mirror breaker")
+                || cn.equals("kinnan, bonder prodigy")
                 || cn.equals("knowledge pool")
+                || cn.equals("kozilek, butcher of truth")
+                || cn.equals("krark-clan ironworks")
+                || cn.equals("krenko, mob boss")
+                || cn.equals("krosan restorer")
+                || cn.equals("laboratory maniac")
+                || cn.equals("land equilibrium")
+                || cn.equals("leonin relic-warder")
+                || cn.equals("leovold, emissary of trest")
+                || cn.equals("leyline of the void")
                 || cn.equals("linvala, keeper of silence")
                 || cn.equals("living death")
                 || cn.equals("llawan, cephalid empress")
                 || cn.equals("loyal retainers")
                 || cn.equals("maelstrom wanderer")
+                || cn.equals("magister sphinx")
                 || cn.equals("malfegor")
-                || cn.equals("master of cruelties")
+                || cn.equals("mana breach")
                 || cn.equals("mana crypt")
                 || cn.equals("mana drain")
                 || cn.equals("mana vault")
+                || cn.equals("mana vortex")
+                || cn.equals("master of cruelties")
+                || cn.equals("memnarch")
+                || cn.equals("meren of clan nel toth")
                 || cn.equals("michiko konda, truth seeker")
+                || cn.equals("mikaeus the unhallowed")
+                || cn.equals("mikaeus, the unhallowed")
+                || cn.equals("mindcrank")
+                || cn.equals("mindslaver")
+                || cn.equals("minion reflector")
+                || cn.equals("mycosynth lattice")
+                || cn.equals("myr turbine")
+                || cn.equals("narset, enlightened master")
+                || cn.equals("narset, parter of veils")
                 || cn.equals("nath of the gilt-leaf")
                 || cn.equals("natural order")
                 || cn.equals("necrotic ooze")
+                || cn.equals("negan, the cold-blooded")
+                || cn.equals("nekusar, the mindrazer")
+                || cn.equals("nether void")
+                || cn.equals("nexus of fate")
                 || cn.equals("nicol bolas")
+                || cn.equals("norin the wary")
+                || cn.equals("notion thief")
                 || cn.equals("numot, the devastator")
                 || cn.equals("oath of druids")
+                || cn.equals("obliterate")
+                || cn.equals("oko, thief of crowns")
+                || cn.equals("oloro, ageless ascetic")
+                || cn.equals("omniscience")
+                || cn.equals("opalescence")
+                || cn.equals("opposition agent")
+                || cn.equals("oppression")
+                || cn.equals("ornithopter")
+                || cn.equals("overwhelming splendor")
+                || cn.equals("palinchron")
+                || cn.equals("paradox engine")
                 || cn.equals("pattern of rebirth")
+                || cn.equals("peregrine drake")
+                || cn.equals("planar portal")
+                || cn.equals("possessed portal")
+                || cn.equals("power artifact")
+                || cn.equals("price of glory")
+                || cn.equals("prossh, skyraider of kher")
                 || cn.equals("protean hulk")
                 || cn.equals("purphoros, god of the forge")
                 || cn.equals("ravages of war")
                 || cn.equals("reclamation sage")
+                || cn.equals("rhystic study")
+                || cn.equals("rick, steadfast leader")
+                || cn.equals("rings of brighthearth")
+                || cn.equals("rising waters")
+                || cn.equals("rite of replication")
+                || cn.equals("ruination")
+                || cn.equals("sanguine bond")
+                || cn.equals("scrambleverse")
+                || cn.equals("seedborn muse")
                 || cn.equals("sen triplets")
+                || cn.equals("sensei's divining top")
                 || cn.equals("serra's sanctum")
                 || cn.equals("sheoldred, whispering one")
+                || cn.equals("sire of insanity")
+                || cn.equals("skithiryx, the blight dragon")
+                || cn.equals("smokestack")
+                || cn.equals("smothering tithe")
                 || cn.equals("sol ring")
+                || cn.equals("sorin markov")
+                || cn.equals("splinter twin")
                 || cn.equals("spore frog")
                 || cn.equals("stasis")
+                || cn.equals("static orb")
+                || cn.equals("stony silence")
+                || cn.equals("storage matrix")
+                || cn.equals("storm cauldron")
                 || cn.equals("strip mine")
-                || cn.equals("the tabernacle at pendrell vale")
-                || cn.equals("tinker")
-                || cn.equals("treasure cruise")
-                || cn.equals("urabrask the hidden")
-                || cn.equals("vorinclex, voice of hunger")
-                || cn.equals("winter orb")
-                || cn.equals("zur the enchanter")) {
-            thisMaxPower = Math.max(thisMaxPower, 5);
-        }
-
-        // Parts of infinite combos
-        if (cn.equals("animate artifact") || cn.equals("animar, soul of element")
-                || cn.equals("archaeomancer")
-                || cn.equals("ashnod's altar") || cn.equals("azami, lady of scrolls")
-                || cn.equals("aura flux")
-                || cn.equals("basalt monolith") || cn.equals("brago, king eternal")
-                || cn.equals("candelabra of tawnos") || cn.equals("cephalid aristocrat")
-                || cn.equals("cephalid illusionist") || cn.equals("changeling berserker")
-                || cn.equals("consecrated sphinx")
-                || cn.equals("cyclonic rift")
-                || cn.equals("the chain veil")
-                || cn.equals("cinderhaze wretch") || cn.equals("cryptic gateway")
-                || cn.equals("deadeye navigator") || cn.equals("derevi, empyrial tactician")
-                || cn.equals("doubling season") || cn.equals("dross scorpion")
-                || cn.equals("earthcraft") || cn.equals("erratic portal")
-                || cn.equals("enter the infinite") || cn.equals("omniscience")
-                || cn.equals("exquisite blood") || cn.equals("future sight")
-                || cn.equals("genesis chamber")
-                || cn.equals("ghave, guru of spores")
-                || cn.equals("grave pact")
-                || cn.equals("grave titan") || cn.equals("great whale")
-                || cn.equals("grim monolith") || cn.equals("gush")
-                || cn.equals("hellkite charger") || cn.equals("intruder alarm")
-                || cn.equals("hermit druid")
-                || cn.equals("humility")
-                || cn.equals("iona, shield of emeria")
-                || cn.equals("karn, silver golem") || cn.equals("kiki-jiki, mirror breaker")
-                || cn.equals("krark-clan ironworks") || cn.equals("krenko, mob boss")
-                || cn.equals("krosan restorer") || cn.equals("laboratory maniac")
-                || cn.equals("leovold, emissary of trest")
-                || cn.equals("leonin relic-warder") || cn.equals("leyline of the void")
-                || cn.equals("memnarch")
-                || cn.equals("meren of clan nel toth") || cn.equals("mikaeus, the unhallowed")
-                || cn.equals("mindcrank") || cn.equals("mindslaver")
-                || cn.equals("minion reflector") || cn.equals("mycosynth lattice")
-                || cn.equals("myr turbine") || cn.equals("narset, enlightened master")
-                || cn.equals("nekusar, the mindrazer") || cn.equals("norin the wary")
-                || cn.equals("notion thief")
-                || cn.equals("opalescence") || cn.equals("ornithopter")
-                || cn.equals("paradox engine")
-                || cn.equals("purphoros, god of the forge")
-                || cn.equals("peregrine drake") || cn.equals("palinchron")
-                || cn.equals("planar portal") || cn.equals("power artifact")
-                || cn.equals("rings of brighthearth") || cn.equals("rite of replication")
-                || cn.equals("sanguine bond") || cn.equals("sensei's divining top")
-                || cn.equals("splinter twin") || cn.equals("stony silence")
                 || cn.equals("sunder")
-                || cn.equals("storm cauldron") || cn.equals("teferi's puzzle box")
+                || cn.equals("survival of the fittest")
+                || cn.equals("table view")
+                || cn.equals("tainted aether")
                 || cn.equals("tangle wire")
+                || cn.equals("tectonic break")
+                || cn.equals("teferi's protection")
+                || cn.equals("teferi's puzzle box")
                 || cn.equals("teferi, mage of zhalfir")
-                || cn.equals("tezzeret the seeker") || cn.equals("time stretch")
-                || cn.equals("time warp") || cn.equals("training grounds")
-                || cn.equals("triskelavus") || cn.equals("triskelion")
-                || cn.equals("turnabout") || cn.equals("umbral mantle")
-                || cn.equals("uyo, silent prophet") || cn.equals("voltaic key")
-                || cn.equals("workhorse") || cn.equals("worldgorger dragon")
-                || cn.equals("worthy cause") || cn.equals("yawgmoth's will")
-                || cn.equals("zealous conscripts")) {
-            thisMaxPower = Math.max(thisMaxPower, 12);
-        }
-
-        if (cn.equals("animar, soul of element")
-                || cn.equals("azami, lady of scrolls")
-                || cn.equals("braids, cabal minion")
-                || cn.equals("child of alara")
-                || cn.equals("derevi, empyrial tactician")
-                || cn.equals("edric, spymaster of trest")
-                || cn.equals("gaddock teeg")
-                || cn.equals("grand arbiter augustin iv")
-                || cn.equals("hokori, dust drinker")
-                || cn.equals("iona, shield of emeria")
-                || cn.equals("jin-gitaxias, core augur")
-                || cn.equals("kaalia of the vast")
-                || cn.equals("karador, ghost chieftain")
-                || cn.equals("leovold, emissary of trest")
-                || cn.equals("linvala, keeper of silence")
-                || cn.equals("llawan, cephalid empress")
-                || cn.equals("memnarch")
-                || cn.equals("meren of clan nel toth")
-                || cn.equals("michiko konda, truth seeker")
-                || cn.equals("narset, enlightened master")
-                || cn.equals("nekusar, the mindrazer")
-                || cn.equals("norin the wary")
-                || cn.equals("numot, the devastator")
-                || cn.equals("sheoldred, whispering one")
-                || cn.equals("teferi, mage of zhalfir")
-                || cn.equals("zur the enchanter")) {
-            thisMaxPower = Math.max(thisMaxPower, 12);
-        }
-
-        if (cn.equals("anafenza, the foremost")
-                || cn.equals("arcum dagsson")
-                || cn.equals("azusa, lost but seeking")
-                || cn.equals("brago, king eternal")
-                || cn.equals("captain sisay")
-                || cn.equals("elesh norn, grand cenobite")
-                || cn.equals("malfegor")
-                || cn.equals("maelstrom wanderer")
-                || cn.equals("mikaeus the unhallowed")
-                || cn.equals("nath of the gilt-leaf")
-                || cn.equals("prossh, skyraider of kher")
-                || cn.equals("purphoros, god of the forge")
-                || cn.equals("sen triplets")
+                || cn.equals("teferi, master of time")
+                || cn.equals("teferi, time raveler")
+                || cn.equals("temporal manipulation")
+                || cn.equals("tergrid, god of fright")
+                || cn.equals("text view")
+                || cn.equals("tezzeret the seeker")
+                || cn.equals("thassa's oracle")
+                || cn.equals("the chain veil")
+                || cn.equals("the tabernacle at pendrell vale")
+                || cn.equals("thieves' auction")
+                || cn.equals("thoughts of ruin")
+                || cn.equals("thrasios, triton hero")
+                || cn.equals("time stretch")
+                || cn.equals("time warp")
+                || cn.equals("tinker")
+                || cn.equals("tooth and nail")
+                || cn.equals("torment of hailfire")
+                || cn.equals("torpor orb")
+                || cn.equals("training grounds")
+                || cn.equals("treasure cruise")
+                || cn.equals("triskelavus")
+                || cn.equals("triskelion")
+                || cn.equals("triumph of the hordes")
+                || cn.equals("turnabout")
+                || cn.equals("ugin, the spirit dragon")
+                || cn.equals("ulamog, the ceaseless hunger")
+                || cn.equals("ulamog, the infinite gyre")
+                || cn.equals("umbral mantle")
                 || cn.equals("urabrask the hidden")
-                || cn.equals("vorinclex, voice of hunger")) {
-            thisMaxPower = Math.max(thisMaxPower, 10);
-        }
+                || cn.equals("urza, lord high artificer")
+                || cn.equals("uyo, silent prophet")
+                || cn.equals("void winnower")
+                || cn.equals("voltaic key")
+                || cn.equals("vorinclex, voice of hunger")
+                || cn.equals("wake of destruction")
+                || cn.equals("warp world")
+                || cn.equals("winter orb")
+                || cn.equals("workhorse")
+                || cn.equals("worldgorger dragon")
+                || cn.equals("worthy cause")
+                || cn.equals("xanathar, guild kingpin")
+                || cn.equals("yawgmoth's will")
+                || cn.equals("zealous conscripts")
+                || cn.equals("zur the enchanter")) {
+                    thisMaxPower = Math.max(thisMaxPower, 12);
+                }
         return thisMaxPower;
     }
+
 }
+
+
diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java
index 5a2e2870d1..92f9d625ce 100644
--- a/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java
+++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java
@@ -225,8 +225,9 @@ public abstract class CardRenderer {
         // Call the template methods
         drawBorder(g);
         drawBackground(g);
+        lessOpaqueRulesTextBox = false;
         drawArt(g);
-        drawFrame(g, attribs, image);
+        drawFrame(g, attribs, image, lessOpaqueRulesTextBox);
         if (!cardView.isAbility()) {
             drawOverlays(g);
             drawCounters(g);
@@ -241,7 +242,7 @@ public abstract class CardRenderer {
 
     protected abstract void drawArt(Graphics2D g);
 
-    protected abstract void drawFrame(Graphics2D g, CardPanelAttributes attribs, BufferedImage image);
+    protected abstract void drawFrame(Graphics2D g, CardPanelAttributes attribs, BufferedImage image, boolean lessOpaqueRulesTextBox);
 
     // Template methods that are possible to override, but unlikely to be
     // overridden.
@@ -318,7 +319,8 @@ public abstract class CardRenderer {
         }
     }
 
-    protected void drawFaceArtIntoRect(Graphics2D g, int x, int y, int w, int h, Rectangle2D artRect, boolean shouldPreserveAspect) {
+    private boolean lessOpaqueRulesTextBox = false;
+    protected void drawFaceArtIntoRect(Graphics2D g, int x, int y, int w, int h, int alternate_h, Rectangle2D artRect, boolean shouldPreserveAspect) {
         // Perform a process to make sure that the art is scaled uniformly to fill the frame, cutting
         // off the minimum amount necessary to make it completely fill the frame without "squashing" it.
         double fullCardImgWidth = faceArtImage.getWidth();
@@ -346,10 +348,18 @@ public abstract class CardRenderer {
                     RenderingHints.KEY_INTERPOLATION,
                     RenderingHints.VALUE_INTERPOLATION_BICUBIC);
             g.setRenderingHints(rh);
-            g.drawImage(faceArtImage,
-                    x, y,
-                    (int) targetWidth, (int) targetHeight,
-                    null);
+            if (fullCardImgWidth > fullCardImgHeight) {
+                g.drawImage(faceArtImage,
+                        x, y,
+                        (int) targetWidth, (int) targetHeight,
+                        null);
+            } else {
+                g.drawImage(faceArtImage,
+                        x, y,
+                        (int) targetWidth, alternate_h, // alernate_h is roughly (targetWidth / 0.74)
+                        null);
+                lessOpaqueRulesTextBox = true;
+            }
         } catch (RasterFormatException e) {
             // At very small card sizes we may encounter a problem with rounding error making the rect not fit
             System.out.println(e);
diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java
index 7d72a9d468..f39cc96b46 100644
--- a/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java
+++ b/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java
@@ -450,9 +450,11 @@ public class ModernCardRenderer extends CardRenderer {
 
             // Normal drawing of art from a source part of the card frame into the rect
             if (useFaceArt) {
+                int alternate_height = cardHeight - boxHeight * 2 - totalContentInset;
                 drawFaceArtIntoRect(g,
                         totalContentInset + 1, totalContentInset + boxHeight,
                         contentWidth - 2, typeLineY - totalContentInset - boxHeight,
+                        alternate_height,
                         sourceRect, shouldPreserveAspect);
             } else if (!isZendikarFullArtLand()) {
                 drawArtIntoRect(g,
@@ -464,14 +466,14 @@ public class ModernCardRenderer extends CardRenderer {
     }
 
     @Override
-    protected void drawFrame(Graphics2D g, CardPanelAttributes attribs, BufferedImage image) {
+    protected void drawFrame(Graphics2D g, CardPanelAttributes attribs, BufferedImage image, boolean lessOpaqueRulesTextBox) {
         // Get the card colors to base the frame on
         ObjectColor frameColors = getFrameObjectColor();
 
         // Get the border paint
         Color boxColor = getBoxColor(frameColors, cardView.getCardTypes(), attribs.isTransformed);
         Color additionalBoxColor = getAdditionalBoxColor(frameColors, cardView.getCardTypes(), attribs.isTransformed);
-        Paint textboxPaint = getTextboxPaint(frameColors, cardView.getCardTypes(), cardWidth);
+        Paint textboxPaint = getTextboxPaint(frameColors, cardView.getCardTypes(), cardWidth, lessOpaqueRulesTextBox);
         Paint borderPaint = getBorderPaint(frameColors, cardView.getCardTypes(), cardWidth);
 
         // Special colors
@@ -1765,21 +1767,29 @@ public class ModernCardRenderer extends CardRenderer {
         }
     }
 
+    private static Color getLessOpaqueColor(Color color, boolean lessOpaqueRulesTextBox) {
+        if (lessOpaqueRulesTextBox) {
+            Color lessOpaque = new Color (color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha() - 50);
+            return lessOpaque;
+        }
+        return color;
+    }
+
     // Determine the border paint to use, based on an ObjectColors
-    protected static Paint getTextboxPaint(ObjectColor colors, Collection<CardType> types, int width) {
+    protected static Paint getTextboxPaint(ObjectColor colors, Collection<CardType> types, int width, boolean lessOpaqueRulesTextBox) {
         if (colors.isMulticolored()) {
             if (colors.getColorCount() == 2) {
                 List<ObjectColor> twoColors = colors.getColors();
                 Color[] translatedColors;
                 if (types.contains(CardType.LAND)) {
                     translatedColors = new Color[]{
-                            getLandTextboxColor(twoColors.get(0)),
-                            getLandTextboxColor(twoColors.get(1))
+                            getLessOpaqueColor(getLandTextboxColor(twoColors.get(0)), lessOpaqueRulesTextBox),
+                            getLessOpaqueColor(getLandTextboxColor(twoColors.get(1)), lessOpaqueRulesTextBox)
                     };
                 } else {
                     translatedColors = new Color[]{
-                            getTextboxColor(twoColors.get(0)),
-                            getTextboxColor(twoColors.get(1))
+                            getLessOpaqueColor(getTextboxColor(twoColors.get(0)), lessOpaqueRulesTextBox),
+                            getLessOpaqueColor(getTextboxColor(twoColors.get(1)), lessOpaqueRulesTextBox)
                     };
                 }
 
@@ -1789,20 +1799,20 @@ public class ModernCardRenderer extends CardRenderer {
                         new float[]{0.4f, 0.6f},
                         translatedColors);
             } else if (types.contains(CardType.LAND)) {
-                return LAND_TEXTBOX_GOLD;
+                return getLessOpaqueColor(LAND_TEXTBOX_GOLD, lessOpaqueRulesTextBox);
             } else {
-                return TEXTBOX_GOLD;
+                return getLessOpaqueColor(TEXTBOX_GOLD, lessOpaqueRulesTextBox);
             }
         } else if (colors.isColorless()) {
             if (types.contains(CardType.LAND)) {
-                return TEXTBOX_LAND;
+                return getLessOpaqueColor(TEXTBOX_LAND, lessOpaqueRulesTextBox);
             } else {
-                return TEXTBOX_COLORLESS;
+                return getLessOpaqueColor(TEXTBOX_COLORLESS, lessOpaqueRulesTextBox);
             }
         } else if (types.contains(CardType.LAND)) {
-            return getLandTextboxColor(colors);
+            return getLessOpaqueColor(getLandTextboxColor(colors), lessOpaqueRulesTextBox);
         } else {
-            return getTextboxColor(colors);
+            return getLessOpaqueColor(getTextboxColor(colors), lessOpaqueRulesTextBox);
         }
     }
 }
diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java
index b732e7faac..6a81bbc6b0 100644
--- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java
+++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java
@@ -586,13 +586,7 @@ public class Commander extends Constructed {
             }
 
             if (card.isPlaneswalker()) {
-                if (card.getName().toLowerCase(Locale.ENGLISH).equals("jace, the mind sculptor")) {
-                    thisMaxPower = Math.max(thisMaxPower, 6);
-                }
-                if (card.getName().toLowerCase(Locale.ENGLISH).equals("ugin, the spirit dragon")) {
-                    thisMaxPower = Math.max(thisMaxPower, 5);
-                }
-                thisMaxPower = Math.max(thisMaxPower, 4);
+                thisMaxPower = Math.max(thisMaxPower, 6);
             }
 
             String cn = card.getName().toLowerCase(Locale.ENGLISH);
@@ -673,7 +667,7 @@ public class Commander extends Constructed {
                     || cn.equals("vorinclex, voice of hunger")
                     || cn.equals("winter orb")
                     || cn.equals("zur the enchanter")) {
-                thisMaxPower = Math.max(thisMaxPower, 5);
+                thisMaxPower = Math.max(thisMaxPower, 12);
             }
 
             // Parts of infinite combos
@@ -734,9 +728,151 @@ public class Commander extends Constructed {
                     || cn.equals("workhorse") || cn.equals("worldgorger dragon")
                     || cn.equals("worthy cause") || cn.equals("yawgmoth's will")
                     || cn.equals("zealous conscripts")) {
-                thisMaxPower = Math.max(thisMaxPower, 12);
+                thisMaxPower = Math.max(thisMaxPower, 15);
                 numberInfinitePieces++;
             }
+
+            // Saltiest cards (edhrec)
+            if (cn.equals("acid rain")
+                    || cn.equals("agent of treachery")
+                    || cn.equals("apocalypse")
+                    || cn.equals("armageddon")
+                    || cn.equals("atraxa, praetors' voice")
+                    || cn.equals("aura shards")
+                    || cn.equals("avacyn, angel of hope")
+                    || cn.equals("back to basics")
+                    || cn.equals("bend or break")
+                    || cn.equals("blightsteel colossus")
+                    || cn.equals("blood moon")
+                    || cn.equals("boil")
+                    || cn.equals("boiling seas")
+                    || cn.equals("bribery")
+                    || cn.equals("burning sands")
+                    || cn.equals("card view")
+                    || cn.equals("cataclysm")
+                    || cn.equals("catastrophe")
+                    || cn.equals("chulane, teller of tales")
+                    || cn.equals("confusion in the ranks")
+                    || cn.equals("consecrated sphinx")
+                    || cn.equals("contamination")
+                    || cn.equals("craterhoof behemoth")
+                    || cn.equals("cyclonic rift")
+                    || cn.equals("death cloud")
+                    || cn.equals("decree of annihilation")
+                    || cn.equals("decree of silence")
+                    || cn.equals("demonic consultation")
+                    || cn.equals("derevi, empyrial tactician")
+                    || cn.equals("devastation")
+                    || cn.equals("divine intervention")
+                    || cn.equals("dockside extortionist")
+                    || cn.equals("doomsday")
+                    || cn.equals("doubling season")
+                    || cn.equals("drannith magistrate")
+                    || cn.equals("elesh norn, grand cenobite")
+                    || cn.equals("embargo")
+                    || cn.equals("emrakul, the promised end")
+                    || cn.equals("epicenter")
+                    || cn.equals("expropriate")
+                    || cn.equals("fall of the thran")
+                    || cn.equals("fierce guardianship")
+                    || cn.equals("food chain")
+                    || cn.equals("force of negation")
+                    || cn.equals("force of will")
+                    || cn.equals("gaddock teeg")
+                    || cn.equals("gaea's cradle")
+                    || cn.equals("gilded drake")
+                    || cn.equals("glenn, the voice of calm")
+                    || cn.equals("global ruin")
+                    || cn.equals("golos, tireless pilgrim")
+                    || cn.equals("grand arbiter augustin iv")
+                    || cn.equals("grip of chaos")
+                    || cn.equals("hokori, dust drinker")
+                    || cn.equals("humility")
+                    || cn.equals("impending disaster")
+                    || cn.equals("invoke prejudice")
+                    || cn.equals("iona, shield of emeria")
+                    || cn.equals("jin-gitaxias, core augur")
+                    || cn.equals("jokulhaups")
+                    || cn.equals("keldon firebombers")
+                    || cn.equals("kinnan, bonder prodigy")
+                    || cn.equals("kozilek, butcher of truth")
+                    || cn.equals("land equilibrium")
+                    || cn.equals("linvala, keeper of silence")
+                    || cn.equals("magister sphinx")
+                    || cn.equals("mana breach")
+                    || cn.equals("mana crypt")
+                    || cn.equals("mana drain")
+                    || cn.equals("mana vortex")
+                    || cn.equals("mindslaver")
+                    || cn.equals("narset, enlightened master")
+                    || cn.equals("narset, parter of veils")
+                    || cn.equals("negan, the cold-blooded")
+                    || cn.equals("nether void")
+                    || cn.equals("nexus of fate")
+                    || cn.equals("notion thief")
+                    || cn.equals("obliterate")
+                    || cn.equals("oko, thief of crowns")
+                    || cn.equals("oloro, ageless ascetic")
+                    || cn.equals("omniscience")
+                    || cn.equals("opposition agent")
+                    || cn.equals("oppression")
+                    || cn.equals("overwhelming splendor")
+                    || cn.equals("palinchron")
+                    || cn.equals("paradox engine")
+                    || cn.equals("possessed portal")
+                    || cn.equals("price of glory")
+                    || cn.equals("protean hulk")
+                    || cn.equals("ravages of war")
+                    || cn.equals("rhystic study")
+                    || cn.equals("rick, steadfast leader")
+                    || cn.equals("rising waters")
+                    || cn.equals("ruination")
+                    || cn.equals("scrambleverse")
+                    || cn.equals("seedborn muse")
+                    || cn.equals("sen triplets")
+                    || cn.equals("sire of insanity")
+                    || cn.equals("skithiryx, the blight dragon")
+                    || cn.equals("smokestack")
+                    || cn.equals("smothering tithe")
+                    || cn.equals("sorin markov")
+                    || cn.equals("stasis")
+                    || cn.equals("static orb")
+                    || cn.equals("storage matrix")
+                    || cn.equals("sunder")
+                    || cn.equals("survival of the fittest")
+                    || cn.equals("table view")
+                    || cn.equals("tainted aether")
+                    || cn.equals("tectonic break")
+                    || cn.equals("teferi's protection")
+                    || cn.equals("teferi, master of time")
+                    || cn.equals("teferi, time raveler")
+                    || cn.equals("temporal manipulation")
+                    || cn.equals("tergrid, god of fright")
+                    || cn.equals("text view")
+                    || cn.equals("thassa's oracle")
+                    || cn.equals("the tabernacle at pendrell vale")
+                    || cn.equals("thieves' auction")
+                    || cn.equals("thoughts of ruin")
+                    || cn.equals("thrasios, triton hero")
+                    || cn.equals("time stretch")
+                    || cn.equals("time warp")
+                    || cn.equals("tooth and nail")
+                    || cn.equals("torment of hailfire")
+                    || cn.equals("torpor orb")
+                    || cn.equals("triumph of the hordes")
+                    || cn.equals("ugin, the spirit dragon")
+                    || cn.equals("ulamog, the ceaseless hunger")
+                    || cn.equals("ulamog, the infinite gyre")
+                    || cn.equals("urza, lord high artificer")
+                    || cn.equals("void winnower")
+                    || cn.equals("vorinclex, voice of hunger")
+                    || cn.equals("wake of destruction")
+                    || cn.equals("warp world")
+                    || cn.equals("winter orb")
+                    || cn.equals("xanathar, guild kingpin")
+                    || cn.equals("zur the enchanter")) {
+                thisMaxPower = Math.max(thisMaxPower, 15);
+            }
             edhPowerLevel += thisMaxPower;
         }
 
@@ -769,11 +905,17 @@ public class Commander extends Constructed {
 
             // Least fun commanders
             if (cn.equals("animar, soul of element")
+                    || cn.equals("anafenza, the foremost")
+                    || cn.equals("arcum dagsson")
                     || cn.equals("azami, lady of scrolls")
+                    || cn.equals("azusa, lost but seeking")
+                    || cn.equals("brago, king eternal")
                     || cn.equals("braids, cabal minion")
+                    || cn.equals("captain sisay")
                     || cn.equals("child of alara")
                     || cn.equals("derevi, empyrial tactician")
                     || cn.equals("edric, spymaster of trest")
+                    || cn.equals("elesh norn, grand cenobite")
                     || cn.equals("gaddock teeg")
                     || cn.equals("grand arbiter augustin iv")
                     || cn.equals("hokori, dust drinker")
@@ -784,41 +926,67 @@ public class Commander extends Constructed {
                     || cn.equals("leovold, emissary of trest")
                     || cn.equals("linvala, keeper of silence")
                     || cn.equals("llawan, cephalid empress")
+                    || cn.equals("maelstrom wanderer")
+                    || cn.equals("malfegor")
                     || cn.equals("memnarch")
                     || cn.equals("meren of clan nel toth")
                     || cn.equals("michiko konda, truth seeker")
+                    || cn.equals("mikaeus the unhallowed")
                     || cn.equals("narset, enlightened master")
+                    || cn.equals("nath of the gilt-leaf")
                     || cn.equals("nekusar, the mindrazer")
                     || cn.equals("norin the wary")
                     || cn.equals("numot, the devastator")
+                    || cn.equals("prossh, skyraider of kher")
+                    || cn.equals("purphoros, god of the forge")
+                    || cn.equals("sen triplets")
                     || cn.equals("sheoldred, whispering one")
                     || cn.equals("teferi, mage of zhalfir")
+                    || cn.equals("urabrask the hidden")
+                    || cn.equals("vorinclex, voice of hunger")
                     || cn.equals("zur the enchanter")) {
                 thisMaxPower = Math.max(thisMaxPower, 25);
             }
 
-            // Next least fun commanders
-            if (cn.equals("anafenza, the foremost")
-                    || cn.equals("arcum dagsson")
-                    || cn.equals("azusa, lost but seeking")
-                    || cn.equals("brago, king eternal")
-                    || cn.equals("captain sisay")
+            // Saltiest commanders
+            if (cn.equals("atraxa, praetors' voice")
+                    || cn.equals("avacyn, angel of hope")
+                    || cn.equals("chulane, teller of tales")
+                    || cn.equals("derevi, empyrial tactician")
                     || cn.equals("elesh norn, grand cenobite")
-                    || cn.equals("malfegor")
-                    || cn.equals("maelstrom wanderer")
-                    || cn.equals("mikaeus the unhallowed")
-                    || cn.equals("nath of the gilt-leaf")
-                    || cn.equals("prossh, skyraider of kher")
-                    || cn.equals("purphoros, god of the forge")
+                    || cn.equals("emrakul, the promised end")
+                    || cn.equals("gaddock teeg")
+                    || cn.equals("glenn, the voice of calm")
+                    || cn.equals("golos, tireless pilgrim")
+                    || cn.equals("grand arbiter augustin iv")
+                    || cn.equals("hokori, dust drinker")
+                    || cn.equals("iona, shield of emeria")
+                    || cn.equals("jin-gitaxias, core augur")
+                    || cn.equals("kinnan, bonder prodigy")
+                    || cn.equals("kozilek, butcher of truth")
+                    || cn.equals("linvala, keeper of silence")
+                    || cn.equals("narset, enlightened master")
+                    || cn.equals("negan, the cold-blooded")
+                    || cn.equals("oko, thief of crowns")
+                    || cn.equals("oloro, ageless ascetic")
+                    || cn.equals("rick, steadfast leader")
                     || cn.equals("sen triplets")
-                    || cn.equals("urabrask the hidden")
-                    || cn.equals("vorinclex, voice of hunger")) {
-                thisMaxPower = Math.max(thisMaxPower, 15);
+                    || cn.equals("skithiryx, the blight dragon")
+                    || cn.equals("teferi, master of time")
+                    || cn.equals("teferi, time raveler")
+                    || cn.equals("thrasios, triton hero")
+                    || cn.equals("ulamog, the ceaseless hunger")
+                    || cn.equals("ulamog, the infinite gyre")
+                    || cn.equals("urza, lord high artificer")
+                    || cn.equals("vorinclex, voice of hunger")
+                    || cn.equals("xanathar, guild kingpin")
+                    || cn.equals("zur the enchanter")) {
+                thisMaxPower = Math.max(thisMaxPower, 20);
             }
             edhPowerLevel += thisMaxPower;
         }
 
-        edhPowerLevel += numberInfinitePieces * 12;
+        edhPowerLevel += numberInfinitePieces * 18;
         edhPowerLevel = Math.round(edhPowerLevel / 10);
         if (edhPowerLevel >= 100) {
             edhPowerLevel = 99;