- Added an option to make planeswalker attacker targeting arrows somewhat darker to make them easier to see on the battlefield.

- Added code support to differentiate stack targeting arrows in color as well (currently not used).
This commit is contained in:
Agetian
2017-08-24 05:48:17 +00:00
parent 2851e51af8
commit 3e4efc22a6
7 changed files with 122 additions and 41 deletions

View File

@@ -106,6 +106,7 @@ public enum CSubmenuPreferences implements ICDoc {
lstControls.add(Pair.of(view.getCbAltSoundSystem(), FPref.UI_ALT_SOUND_SYSTEM));
lstControls.add(Pair.of(view.getCbUiForTouchScreen(), FPref.UI_FOR_TOUCHSCREN));
lstControls.add(Pair.of(view.getCbTimedTargOverlay(), FPref.UI_TIMED_TARGETING_OVERLAY_UPDATES));
lstControls.add(Pair.of(view.getCbTargOverlayDarkArrows(), FPref.UI_TARGETING_DARKER_PW_ARROWS));
lstControls.add(Pair.of(view.getCbCompactMainMenu(), FPref.UI_COMPACT_MAIN_MENU));
lstControls.add(Pair.of(view.getCbPromptFreeBlocks(), FPref.MATCHPREF_PROMPT_FREE_BLOCKS));
lstControls.add(Pair.of(view.getCbPauseWhileMinimized(), FPref.UI_PAUSE_WHILE_MINIMIZED));

View File

@@ -80,6 +80,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
private final JCheckBox cbAltSoundSystem = new OptionsCheckBox("Use Alternate Sound System");
private final JCheckBox cbUiForTouchScreen = new OptionsCheckBox("Enhance UI for Touchscreens");
private final JCheckBox cbTimedTargOverlay = new OptionsCheckBox("Enable Targeting Overlay Optimization");
private final JCheckBox cbTargOverlayDarkArrows = new OptionsCheckBox("Darker Arrows for Planeswalker Attackers");
private final JCheckBox cbCompactMainMenu = new OptionsCheckBox("Use Compact Main Sidebar Menu");
private final JCheckBox cbDetailedPaymentDesc = new OptionsCheckBox("Spell Description in Payment Prompt");
private final JCheckBox cbPromptFreeBlocks = new OptionsCheckBox("Free Block Handling");
@@ -276,7 +277,10 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
pnlPrefs.add(new NoteLabel("Stacks identical creatures on the battlefield like lands, artifacts, and enchantments."), descriptionConstraints);
pnlPrefs.add(cbTimedTargOverlay, titleConstraints);
pnlPrefs.add(new NoteLabel("Enables throttling-based optimization of targeting overlay to reduce CPU use (only disable if you experience choppiness on older hardware, requires starting a new match)"), descriptionConstraints);
pnlPrefs.add(new NoteLabel("Enables throttling-based optimization of targeting overlay to reduce CPU use (only disable if you experience choppiness on older hardware, requires starting a new match)."), descriptionConstraints);
pnlPrefs.add(cbTargOverlayDarkArrows, titleConstraints);
pnlPrefs.add(new NoteLabel("Makes the targeting overlay arrows darker for creatures attacking planeswalkers, to make those arrows easier to distinguish from the blocker arrows."), descriptionConstraints);
pnlPrefs.add(cbpCounterDisplayType, comboBoxConstraints);
pnlPrefs.add(new NoteLabel("Selects the style of the in-game counter display for cards. Text-based is a new tab-like display on the cards. Image-based is the old counter image. Hybrid displays both at once."), descriptionConstraints);
@@ -640,6 +644,11 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
return cbTimedTargOverlay;
}
/** @return {@link javax.swing.JCheckBox} */
public JCheckBox getCbTargOverlayDarkArrows() {
return cbTargOverlayDarkArrows;
}
public final JCheckBox getCbUiForTouchScreen() {
return cbUiForTouchScreen;
}

View File

@@ -64,7 +64,8 @@ public class TargetingOverlay {
private final CMatchUI matchUI;
private final OverlayPanel pnl = new OverlayPanel();
private final List<CardPanel> cardPanels = new ArrayList<CardPanel>();
private final List<Arc> arcsFoe = new ArrayList<Arc>();
private final List<Arc> arcsFoeAtk = new ArrayList<Arc>();
private final List<Arc> arcsFoeDef = new ArrayList<Arc>();
private final List<Arc> arcsFriend = new ArrayList<Arc>();
private final ArcAssembler assembler = new ArcAssembler();
private final Set<Integer> stackItemIDs = new HashSet<Integer>();
@@ -87,6 +88,14 @@ public class TargetingOverlay {
private int allowedUpdates = 0;
private final int MAX_CONSECUTIVE_UPDATES = 1;
private enum ArcConnection {
Friends,
FoesAttacking,
FoesBlocking,
FriendsStackTargeting,
FoesStackTargeting
}
/**
* Semi-transparent overlay panel. Should be used with layered panes.
*/
@@ -107,7 +116,8 @@ public class TargetingOverlay {
// Re-added as the new version was causing issues for at least one user.
private void assembleArcs(final CombatView combat) {
//List<VField> fields = VMatchUI.SINGLETON_INSTANCE.getFieldViews();
arcsFoe.clear();
arcsFoeAtk.clear();
arcsFoeDef.clear();
arcsFriend.clear();
cardPanels.clear();
cardsVisualized.clear();
@@ -183,12 +193,14 @@ public class TargetingOverlay {
PlayerView activator = instance.getActivatingPlayer();
while (instance != null) {
for (CardView c : instance.getTargetCards()) {
addArc(endpoints.get(c.getId()), itemLocOnScreen, activator.isOpponentOf(c.getController()));
addArc(endpoints.get(c.getId()), itemLocOnScreen, activator.isOpponentOf(c.getController()) ?
ArcConnection.FoesStackTargeting : ArcConnection.FriendsStackTargeting);
}
for (PlayerView p : instance.getTargetPlayers()) {
Point point = getPlayerTargetingArrowPoint(p, locOnScreen);
if(point != null) {
addArc(point, itemLocOnScreen, activator.isOpponentOf(p));
addArc(point, itemLocOnScreen, activator.isOpponentOf(p) ?
ArcConnection.FoesStackTargeting : ArcConnection.FriendsStackTargeting);
}
}
instance = instance.getSubInstance();
@@ -232,7 +244,8 @@ public class TargetingOverlay {
}
}
//List<VField> fields = VMatchUI.SINGLETON_INSTANCE.getFieldViews();
arcsFoe.clear();
arcsFoeAtk.clear();
arcsFoeDef.clear();
arcsFriend.clear();
cardPanels.clear();
cardsVisualized.clear();
@@ -339,12 +352,14 @@ public class TargetingOverlay {
PlayerView activator = instance.getActivatingPlayer();
while (instance != null) {
for (CardView c : instance.getTargetCards()) {
addArc(endpoints.get(c.getId()), itemLocOnScreen, activator.isOpponentOf(c.getController()));
addArc(endpoints.get(c.getId()), itemLocOnScreen, activator.isOpponentOf(c.getController()) ?
ArcConnection.FoesStackTargeting : ArcConnection.FriendsStackTargeting);
}
for (PlayerView p : instance.getTargetPlayers()) {
Point point = getPlayerTargetingArrowPoint(p, locOnScreen);
if (point != null) {
addArc(point, itemLocOnScreen, activator.isOpponentOf(p));
addArc(point, itemLocOnScreen, activator.isOpponentOf(p) ?
ArcConnection.FoesStackTargeting : ArcConnection.FriendsStackTargeting);
}
}
instance = instance.getSubInstance();
@@ -365,16 +380,22 @@ public class TargetingOverlay {
return point;
}
private void addArc(Point end, Point start, boolean connectsFoes) {
private void addArc(Point end, Point start, ArcConnection connects) {
if (start == null || end == null) {
return;
}
if (connectsFoes) {
arcsFoe.add(new Arc(end, start));
}
else {
switch (connects) {
case Friends:
case FriendsStackTargeting:
arcsFriend.add(new Arc(end, start));
break;
case FoesAttacking:
arcsFoeAtk.add(new Arc(end, start));
break;
case FoesBlocking:
case FoesStackTargeting:
arcsFoeDef.add(new Arc(end, start));
}
}
@@ -393,26 +414,26 @@ public class TargetingOverlay {
if (null != enchanting) {
if (enchanting.getController() != null && !enchanting.getController().equals(c.getController())) {
addArc(endpoints.get(enchanting.getId()), endpoints.get(c.getId()), false);
addArc(endpoints.get(enchanting.getId()), endpoints.get(c.getId()), ArcConnection.Friends);
cardsVisualized.add(enchanting);
}
}
if (null != equipping) {
if (equipping.getController() != null && !equipping.getController().equals(c.getController())) {
addArc(endpoints.get(equipping.getId()), endpoints.get(c.getId()), false);
addArc(endpoints.get(equipping.getId()), endpoints.get(c.getId()), ArcConnection.Friends);
cardsVisualized.add(equipping);
}
}
if (null != fortifying) {
if (fortifying.getController() != null && !fortifying.getController().equals(c.getController())) {
addArc(endpoints.get(fortifying.getId()), endpoints.get(c.getId()), false);
addArc(endpoints.get(fortifying.getId()), endpoints.get(c.getId()), ArcConnection.Friends);
cardsVisualized.add(fortifying);
}
}
if (null != enchantedBy) {
for (final CardView enc : enchantedBy) {
if (enc.getController() != null && !enc.getController().equals(c.getController())) {
addArc(endpoints.get(c.getId()), endpoints.get(enc.getId()), false);
addArc(endpoints.get(c.getId()), endpoints.get(enc.getId()), ArcConnection.Friends);
cardsVisualized.add(enc);
}
}
@@ -420,7 +441,7 @@ public class TargetingOverlay {
if (null != equippedBy) {
for (final CardView eq : equippedBy) {
if (eq.getController() != null && !eq.getController().equals(c.getController())) {
addArc(endpoints.get(c.getId()), endpoints.get(eq.getId()), false);
addArc(endpoints.get(c.getId()), endpoints.get(eq.getId()), ArcConnection.Friends);
cardsVisualized.add(eq);
}
}
@@ -428,31 +449,31 @@ public class TargetingOverlay {
if (null != fortifiedBy) {
for (final CardView eq : fortifiedBy) {
if (eq.getController() != null && !eq.getController().equals(c.getController())) {
addArc(endpoints.get(c.getId()), endpoints.get(eq.getId()), false);
addArc(endpoints.get(c.getId()), endpoints.get(eq.getId()), ArcConnection.Friends);
cardsVisualized.add(eq);
}
}
}
if (null != paired) {
addArc(endpoints.get(paired.getId()), endpoints.get(c.getId()), false);
addArc(endpoints.get(paired.getId()), endpoints.get(c.getId()), ArcConnection.Friends);
cardsVisualized.add(paired);
}
if (null != combat) {
final GameEntityView defender = combat.getDefender(c);
// if c is attacking a planeswalker
if (defender instanceof CardView) {
addArc(endpoints.get(defender.getId()), endpoints.get(c.getId()), true);
addArc(endpoints.get(defender.getId()), endpoints.get(c.getId()), ArcConnection.FoesAttacking);
}
// if c is a planeswalker that's being attacked
for (final CardView pwAttacker : combat.getAttackersOf(c)) {
addArc(endpoints.get(c.getId()), endpoints.get(pwAttacker.getId()), true);
addArc(endpoints.get(c.getId()), endpoints.get(pwAttacker.getId()), ArcConnection.FoesAttacking);
}
for (final CardView attackingCard : combat.getAttackers()) {
final Iterable<CardView> cards = combat.getPlannedBlockers(attackingCard);
if (cards == null) continue;
for (final CardView blockingCard : cards) {
if (!attackingCard.equals(c) && !blockingCard.equals(c)) { continue; }
addArc(endpoints.get(attackingCard.getId()), endpoints.get(blockingCard.getId()), true);
addArc(endpoints.get(attackingCard.getId()), endpoints.get(blockingCard.getId()), ArcConnection.FoesBlocking);
cardsVisualized.add(blockingCard);
}
cardsVisualized.add(attackingCard);
@@ -552,6 +573,7 @@ public class TargetingOverlay {
super.paintComponent(g);
final ArcState overlaystate = matchUI.getCDock().getArcState();
final boolean darkerPWArrows = FModel.getPreferences().getPrefBoolean(FPref.UI_TARGETING_DARKER_PW_ARROWS);
// Arcs are off
if (overlaystate == ArcState.OFF) { return; }
@@ -568,7 +590,7 @@ public class TargetingOverlay {
}
}
if (arcsFoe.isEmpty() && arcsFriend.isEmpty()) {
if (arcsFoeAtk.isEmpty() && arcsFoeDef.isEmpty() && arcsFriend.isEmpty()) {
if (assembled) {
// We still need to repaint to get rid of visual artifacts
// The original (non-throttled) code did not do this repaint.
@@ -589,9 +611,12 @@ public class TargetingOverlay {
if (colorCombat.getAlpha() == 0) {
colorCombat = new Color(255, 0, 0, 153);
}
// For planeswalker attackers, use a somewhat darker shade if the player opts in
Color colorCombatAtk = darkerPWArrows ? colorCombat.darker() : colorCombat;
drawArcs(g2d, colorOther, arcsFriend);
drawArcs(g2d, colorCombat, arcsFoe);
drawArcs(g2d, colorCombatAtk, arcsFoeAtk);
drawArcs(g2d, colorCombat, arcsFoeDef);
if (assembled || !useThrottling) {
FView.SINGLETON_INSTANCE.getFrame().repaint(); // repaint the match UI

View File

@@ -22,6 +22,8 @@ import forge.assets.FSkinColor;
import forge.assets.FSkinColor.Colors;
import forge.game.card.CardView;
import forge.game.player.PlayerView;
import forge.model.FModel;
import forge.properties.ForgePreferences;
import forge.screens.match.views.VCardDisplayArea.CardAreaPanel;
import forge.toolbox.FDisplayObject;
import forge.util.Utils;
@@ -33,47 +35,84 @@ public class TargetingOverlay {
private static final float BORDER_THICKNESS = Utils.scale(1);
private static final float ARROW_THICKNESS = Utils.scale(5);
private static final float ARROW_SIZE = 3 * ARROW_THICKNESS;
private static FSkinColor friendColor, foeColor;
private static FSkinColor friendColor, foeAtkColor, foeDefColor;
public enum ArcConnection {
Friends,
FoesAttacking,
FoesBlocking,
FriendsStackTargeting,
FoesStackTargeting
}
public static void updateColors() {
final boolean darkerPWArrows = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_TARGETING_DARKER_PW_ARROWS);
friendColor = FSkinColor.get(Colors.CLR_NORMAL_TARGETING_ARROW);
if (friendColor.getAlpha() == 0) {
friendColor = FSkinColor.get(Colors.CLR_ACTIVE).alphaColor(153f / 255f);
}
foeColor = FSkinColor.get(Colors.CLR_COMBAT_TARGETING_ARROW);
if (foeColor.getAlpha() == 0) {
foeColor = FSkinColor.getStandardColor(new Color(1, 0, 0, 153 / 255f));
foeDefColor = FSkinColor.get(Colors.CLR_COMBAT_TARGETING_ARROW);
if (foeDefColor.getAlpha() == 0) {
foeDefColor = FSkinColor.getStandardColor(new Color(1, 0, 0, 153 / 255f));
}
foeAtkColor = darkerPWArrows ? foeDefColor.darker().stepColor(-60) : foeDefColor;
}
private TargetingOverlay() {
}
public static void drawArrow(Graphics g, CardView startCard, CardView endCard) {
ArcConnection connects;
if (startCard.getOwner().isOpponentOf((endCard.getOwner()))) {
if (startCard.isAttacking()) {
connects = ArcConnection.FoesAttacking;
} else {
connects = ArcConnection.FoesBlocking;
}
} else {
connects = ArcConnection.Friends;
}
drawArrow(g, CardAreaPanel.get(startCard).getTargetingArrowOrigin(),
CardAreaPanel.get(endCard).getTargetingArrowOrigin(),
startCard.getOwner().isOpponentOf(endCard.getOwner()));
connects);
}
public static void drawArrow(Graphics g, Vector2 start, CardView targetCard, boolean connectsFoes) {
public static void drawArrow(Graphics g, Vector2 start, CardView targetCard, ArcConnection connects) {
drawArrow(g, start,
CardAreaPanel.get(targetCard).getTargetingArrowOrigin(),
connectsFoes);
connects);
}
public static void drawArrow(Graphics g, Vector2 start, PlayerView targetPlayer, boolean connectsFoes) {
public static void drawArrow(Graphics g, Vector2 start, PlayerView targetPlayer, ArcConnection connects) {
drawArrow(g, start,
MatchController.getView().getPlayerPanel(targetPlayer).getAvatar().getTargetingArrowOrigin(),
connectsFoes);
connects);
}
public static void drawArrow(Graphics g, FDisplayObject startCardDisplay, FDisplayObject endCardDisplay, boolean connectsFoes) {
public static void drawArrow(Graphics g, FDisplayObject startCardDisplay, FDisplayObject endCardDisplay, ArcConnection connects) {
drawArrow(g, CardAreaPanel.getTargetingArrowOrigin(startCardDisplay, false),
CardAreaPanel.getTargetingArrowOrigin(endCardDisplay, false),
connectsFoes);
connects);
}
public static void drawArrow(Graphics g, Vector2 start, Vector2 end, boolean connectsFoes) {
public static void drawArrow(Graphics g, Vector2 start, Vector2 end, ArcConnection connects) {
if (start == null || end == null) { return; }
FSkinColor color = connectsFoes ? foeColor : friendColor;
FSkinColor color = foeDefColor;
switch (connects) {
case Friends:
case FriendsStackTargeting:
color = friendColor;
break;
case FoesAttacking:
color = foeAtkColor;
break;
case FoesBlocking:
case FoesStackTargeting:
color = foeDefColor;
}
g.drawArrow(BORDER_THICKNESS, ARROW_THICKNESS, ARROW_SIZE, color, start.x, start.y, end.x, end.y);
}
}

View File

@@ -213,10 +213,12 @@ public class VStack extends FDropDown {
StackItemView instance = activeStackInstance;
while (instance != null) {
for (CardView c : instance.getTargetCards()) {
TargetingOverlay.drawArrow(g, arrowOrigin, c, activator.isOpponentOf(c.getController()));
TargetingOverlay.ArcConnection conn = activator.isOpponentOf(c.getController()) ? TargetingOverlay.ArcConnection.FoesStackTargeting : TargetingOverlay.ArcConnection.FriendsStackTargeting;
TargetingOverlay.drawArrow(g, arrowOrigin, c, conn);
}
for (PlayerView p : instance.getTargetPlayers()) {
TargetingOverlay.drawArrow(g, arrowOrigin, p, activator.isOpponentOf(p));
TargetingOverlay.ArcConnection conn = activator.isOpponentOf(p) ? TargetingOverlay.ArcConnection.FoesStackTargeting : TargetingOverlay.ArcConnection.FriendsStackTargeting;
TargetingOverlay.drawArrow(g, arrowOrigin, p, conn);
}
instance = instance.getSubInstance();
}

View File

@@ -139,6 +139,10 @@ public class SettingsPage extends TabPage<SettingsScreen> {
"Use Escape Key To End Turn",
"Allows to use Esc keyboard shortcut to end turn prematurely"),
1);
lstSettings.addItem(new BooleanSetting(FPref.UI_TARGETING_DARKER_PW_ARROWS,
"Darker Arrows for Planeswalker Attackers",
"Makes targeting arrows darker for creatures attacking planeswalkers."),
1);
//Random Deck Generation
lstSettings.addItem(new BooleanSetting(FPref.DECKGEN_NOSMALL,

View File

@@ -72,6 +72,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
UI_PREFERRED_AVATARS_ONLY ("false"),
UI_TARGETING_OVERLAY ("0"),
UI_TIMED_TARGETING_OVERLAY_UPDATES ("true"),
UI_TARGETING_DARKER_PW_ARROWS ("true"),
UI_ENABLE_SOUNDS ("true"),
UI_ENABLE_MUSIC ("true"),
UI_ALT_SOUND_SYSTEM ("false"),