diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index 0d89701881b..4b67aa8d10e 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -970,6 +970,9 @@ public class GameAction { for (final Player p : game.getPlayers()) { for (final ZoneType zt : ZoneType.values()) { + if (zt == ZoneType.Command) + p.checkKeywordCard(); + if (zt == ZoneType.Battlefield) { continue; } diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 2c383929ba9..e2aca484aa1 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -1156,6 +1156,7 @@ public class Player extends GameEntity implements Comparable { } } view.updateKeywords(this); + updateKeywordCardAbilityText(); } public final KeywordCollectionView getKeywords() { @@ -2969,7 +2970,49 @@ public class Player extends GameEntity implements Comparable { this.updateZoneForView(com); } } - + public void updateKeywordCardAbilityText() { + if(getKeywordCard() == null) + return; + final PlayerZone com = getZone(ZoneType.Command); + keywordEffect.setText(""); + keywordEffect.updateAbilityTextForView(); + boolean headerAdded = false; + StringBuilder kw = new StringBuilder(); + for(String k : keywords) { + if(!headerAdded) { + headerAdded = true; + kw.append(this.getName()).append(" has: \n"); + } + kw.append(k).append("\n"); + } + if(!kw.toString().isEmpty()) { + keywordEffect.setText(trimKeywords(kw.toString())); + keywordEffect.updateAbilityTextForView(); + } + this.updateZoneForView(com); + } + public String trimKeywords(String keywordTexts) { + keywordTexts = TextUtil.fastReplace(keywordTexts,":Card.named", " from "); + keywordTexts = TextUtil.fastReplace(keywordTexts, ":Card.Black:", " from "); + keywordTexts = TextUtil.fastReplace(keywordTexts, ":Card.Blue:", " from "); + keywordTexts = TextUtil.fastReplace(keywordTexts, ":Card.Red:", " from "); + keywordTexts = TextUtil.fastReplace(keywordTexts, ":Card.Green:", " from "); + keywordTexts = TextUtil.fastReplace(keywordTexts, ":Card.White:", " from "); + keywordTexts = TextUtil.fastReplace(keywordTexts, ":Card.MonoColor:", " from "); + keywordTexts = TextUtil.fastReplace(keywordTexts, ":Card.MultiColor:", " from "); + keywordTexts = TextUtil.fastReplace(keywordTexts, ":Card.Colorless:", " from "); + return keywordTexts; + } + public void checkKeywordCard() { + if (keywordEffect == null) + return; + final PlayerZone com = getZone(ZoneType.Command); + if (keywordEffect.getAbilityText().isEmpty()) { + com.remove(keywordEffect); + this.updateZoneForView(com); + keywordEffect = null; + } + } public boolean hasBlessing() { return blessingEffect != null; } diff --git a/forge-gui-desktop/src/main/java/forge/toolbox/CardFaceSymbols.java b/forge-gui-desktop/src/main/java/forge/toolbox/CardFaceSymbols.java index d6196af6376..be902dbab4f 100644 --- a/forge-gui-desktop/src/main/java/forge/toolbox/CardFaceSymbols.java +++ b/forge-gui-desktop/src/main/java/forge/toolbox/CardFaceSymbols.java @@ -125,6 +125,7 @@ public class CardFaceSymbols { MANA_IMAGES.put("doublestrike", FSkin.getImage(FSkinProp.IMG_ABILITY_DOUBLE_STRIKE)); MANA_IMAGES.put("firststrike", FSkin.getImage(FSkinProp.IMG_ABILITY_FIRST_STRIKE)); MANA_IMAGES.put("fear", FSkin.getImage(FSkinProp.IMG_ABILITY_FEAR)); + MANA_IMAGES.put("flash", FSkin.getImage(FSkinProp.IMG_ABILITY_FLASH)); MANA_IMAGES.put("flying", FSkin.getImage(FSkinProp.IMG_ABILITY_FLYING)); MANA_IMAGES.put("hexproof", FSkin.getImage(FSkinProp.IMG_ABILITY_HEXPROOF)); MANA_IMAGES.put("indestructible", FSkin.getImage(FSkinProp.IMG_ABILITY_INDESTRUCTIBLE)); diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java b/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java index 641619e9a9c..fe0752e57ab 100644 --- a/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java @@ -96,6 +96,7 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl private boolean isAnimationPanel; private int cardXOffset, cardYOffset, cardWidth, cardHeight; private boolean isSelected; + private boolean hasFlash; private CachedCardImage cachedImage; private static Font smallCounterFont; @@ -285,6 +286,13 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl g2d.fillRoundRect(cardXOffset - n, (cardYOffset - n) + offset, cardWidth + (n * 2), cardHeight + (n * 2), cornerSize + n , cornerSize + n); } + //card with flash.. + if (hasFlash) { + g2d.setColor(Color.cyan); + final int n = Math.max(1, Math.round(cardWidth * CardPanel.SELECTED_BORDER_SIZE)); + g2d.fillRoundRect(cardXOffset - n, (cardYOffset - n) + offset, cardWidth + (n * 2), cardHeight + (n * 2), cornerSize + n , cornerSize + n); + } + // Black fill - (will become an outline for white bordered cards) g2d.setColor(Color.black); g2d.fillRoundRect(cardXOffset, cardYOffset + offset, cardWidth, cardHeight, cornerSize, cornerSize); @@ -512,6 +520,7 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl int abiX = cardXOffset + (cardWidth / 2) + (cardWidth / 3); int abiSpace = (cardWidth / 7); int abiY = cardWidth < 200 ? cardYOffset + 25 : cardYOffset + 50; + hasFlash = false; if (ZoneType.Battlefield.equals(card.getZone()) && showAbilityIcons()){ if (card.getCurrentState().hasFlying()) { CardFaceSymbols.drawAbilitySymbol("flying", g, abiX, abiY, abiScale, abiScale); @@ -681,6 +690,17 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl abiY += abiSpace; } } + } else if (!ZoneType.Battlefield.equals(card.getZone()) && showAbilityIcons()){ + String keywordKey = card.getCurrentState().getKeywordKey(); + String abilityText = card.getCurrentState().getAbilityText(); + if ((keywordKey.indexOf("Flash") != -1) + || ((abilityText.indexOf("May be played by") != -1) + && (abilityText.indexOf("and as though it has flash") != -1))){ + if (keywordKey.indexOf("Flashback") == -1) { + hasFlash = true; + CardFaceSymbols.drawAbilitySymbol("flash", g, cardXOffset + (cardWidth / 2) + (cardWidth / 3), cardWidth < 200 ? cardYOffset + 25 : cardYOffset + 50, cardWidth / 7, cardWidth / 7); + } + } } } diff --git a/forge-gui-mobile/src/forge/Graphics.java b/forge-gui-mobile/src/forge/Graphics.java index 366eecc54bf..a5df4f53ca7 100644 --- a/forge-gui-mobile/src/forge/Graphics.java +++ b/forge-gui-mobile/src/forge/Graphics.java @@ -145,7 +145,7 @@ public class Graphics { displayObj.draw(this); if (displayObj.getRotate90() || displayObj.getRotate180()) { - endTransform(); + endTransform(); } visibleBounds = backup; @@ -624,19 +624,17 @@ public class Graphics { public void startRotateTransform(float originX, float originY, float rotation) { batch.end(); - float dx = adjustX(originX); - float dy = adjustY(originY, 0); - transforms.add(new Matrix4(batch.getTransformMatrix())); //backup current transform matrix - batch.getTransformMatrix().translate(dx, dy, 0); - batch.getTransformMatrix().rotate(Vector3.Z, rotation); - batch.getTransformMatrix().translate(-dx, -dy, 0); + transforms.add(0, new Matrix4(batch.getTransformMatrix().idt())); //startshape is using this above as reference + batch.getTransformMatrix().idt().translate(adjustX(originX), adjustY(originY, 0), 0).rotate(Vector3.Z, rotation).translate(-adjustX(originX), -adjustY(originY, 0), 0); batch.begin(); } public void endTransform() { batch.end(); - batch.getTransformMatrix().set(transforms.pop()); - shapeRenderer.setTransformMatrix(batch.getTransformMatrix()); + shapeRenderer.setTransformMatrix(batch.getTransformMatrix().idt()); + transforms.pop(); + batch.getTransformMatrix().idt(); //reset + shapeRenderer.getTransformMatrix().idt(); //reset batch.begin(); } diff --git a/forge-gui-mobile/src/forge/assets/FSkinImage.java b/forge-gui-mobile/src/forge/assets/FSkinImage.java index 38daeb2ced1..5926e5e05e8 100644 --- a/forge-gui-mobile/src/forge/assets/FSkinImage.java +++ b/forge-gui-mobile/src/forge/assets/FSkinImage.java @@ -357,6 +357,7 @@ public enum FSkinImage implements FImage { IMG_ABILITY_DOUBLE_STRIKE (FSkinProp.IMG_ABILITY_DOUBLE_STRIKE, SourceFile.ABILITIES), IMG_ABILITY_FIRST_STRIKE (FSkinProp.IMG_ABILITY_FIRST_STRIKE, SourceFile.ABILITIES), IMG_ABILITY_FEAR (FSkinProp.IMG_ABILITY_FEAR, SourceFile.ABILITIES), + IMG_ABILITY_FLASH (FSkinProp.IMG_ABILITY_FLASH, SourceFile.ABILITIES), IMG_ABILITY_FLYING (FSkinProp.IMG_ABILITY_FLYING, SourceFile.ABILITIES), IMG_ABILITY_HASTE (FSkinProp.IMG_ABILITY_HASTE, SourceFile.ABILITIES), IMG_ABILITY_HEXPROOF (FSkinProp.IMG_ABILITY_HEXPROOF, SourceFile.ABILITIES), diff --git a/forge-gui-mobile/src/forge/card/CardFaceSymbols.java b/forge-gui-mobile/src/forge/card/CardFaceSymbols.java index 7a2213747a2..b82ad3aae11 100644 --- a/forge-gui-mobile/src/forge/card/CardFaceSymbols.java +++ b/forge-gui-mobile/src/forge/card/CardFaceSymbols.java @@ -108,6 +108,7 @@ public class CardFaceSymbols { MANA_IMAGES.put("doublestrike", FSkinImage.IMG_ABILITY_DOUBLE_STRIKE); MANA_IMAGES.put("firststrike", FSkinImage.IMG_ABILITY_FIRST_STRIKE); MANA_IMAGES.put("fear", FSkinImage.IMG_ABILITY_FEAR); + MANA_IMAGES.put("flash", FSkinImage.IMG_ABILITY_FLASH); MANA_IMAGES.put("flying", FSkinImage.IMG_ABILITY_FLYING); MANA_IMAGES.put("haste", FSkinImage.IMG_ABILITY_HASTE); MANA_IMAGES.put("hexproof", FSkinImage.IMG_ABILITY_HEXPROOF); diff --git a/forge-gui-mobile/src/forge/card/CardRenderer.java b/forge-gui-mobile/src/forge/card/CardRenderer.java index d4a04841adc..6dd24b6d0b8 100644 --- a/forge-gui-mobile/src/forge/card/CardRenderer.java +++ b/forge-gui-mobile/src/forge/card/CardRenderer.java @@ -882,6 +882,16 @@ public class CardRenderer { abiCount += 1; } } + } else if (canShow && !onbattlefield && showAbilityIcons(card)) { + //draw indicator for flash or can be cast at instant speed, enabled if show ability icons is enabled + String keywordKey = card.getCurrentState().getKeywordKey(); + String abilityText = card.getCurrentState().getAbilityText(); + if ((keywordKey.indexOf("Flash") != -1) + || ((abilityText.indexOf("May be played by") != -1) + && (abilityText.indexOf("and as though it has flash") != -1))){ + if (keywordKey.indexOf("Flashback") == -1) + CardFaceSymbols.drawSymbol("flash", g, cx + ((cw*2)/2.3f), cy, cw / 5.5f, cw / 5.5f); + } } //draw name and mana cost overlays if card is small or default card image being used if (h <= NAME_COST_THRESHOLD && canShow) { diff --git a/forge-gui-mobile/src/forge/screens/match/MatchController.java b/forge-gui-mobile/src/forge/screens/match/MatchController.java index a438e2510ed..3d6762b6c07 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchController.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchController.java @@ -30,7 +30,6 @@ import forge.card.GameEntityPicker; import forge.deck.CardPool; import forge.deck.FSideboardDialog; import forge.game.GameEntityView; -import forge.game.GameView; import forge.game.card.CardView; import forge.game.phase.PhaseType; import forge.game.player.DelayedReveal; @@ -70,8 +69,6 @@ public class MatchController extends AbstractGuiGame { private static final Map avatarImages = new HashMap<>(); - private static final Map sleeveImages = new HashMap<>(); - private static HostedMatch hostedMatch; private static MatchScreen view; @@ -107,12 +104,7 @@ public class MatchController extends AbstractGuiGame { public static FImage getPlayerSleeve(final PlayerView p) { if (p == null) return FSkinImage.UNKNOWN; - final String lp = p.getLobbyPlayerName(); - FImage sleeve = sleeveImages.get(lp); - if (sleeve == null) { - sleeve = new FTextureRegionImage(FSkin.getSleeves().get(p.getSleeveIndex())); - } - return sleeve; + return new FTextureRegionImage(FSkin.getSleeves().get(p.getSleeveIndex())); } @Override @@ -208,13 +200,16 @@ public class MatchController extends AbstractGuiGame { @Override public void updatePhase() { - final GameView gameView = getGameView(); - final PlayerView p = gameView.getPlayerTurn(); - final PhaseType ph = gameView.getPhase(); + final PlayerView p = getGameView().getPlayerTurn(); + final PhaseType ph = getGameView().getPhase(); PhaseLabel lbl = null; - if(p != null && ph != null) - lbl = view.getPlayerPanel(p).getPhaseIndicator().getLabel(ph); + + if(ph!=null) { + lbl = p == null ? null : view.getPlayerPanel(p).getPhaseIndicator().getLabel(ph); + } else { + System.err.println("getGameView().getPhase() returned 'null'"); + } view.resetAllPhaseButtons(); if (lbl != null) { diff --git a/forge-gui/res/skins/default/sprite_ability.png b/forge-gui/res/skins/default/sprite_ability.png index a42a706c686..7b25e07fcbe 100644 Binary files a/forge-gui/res/skins/default/sprite_ability.png and b/forge-gui/res/skins/default/sprite_ability.png differ diff --git a/forge-gui/src/main/java/forge/assets/FSkinProp.java b/forge-gui/src/main/java/forge/assets/FSkinProp.java index 38edff0ea32..6b124b29dba 100644 --- a/forge-gui/src/main/java/forge/assets/FSkinProp.java +++ b/forge-gui/src/main/java/forge/assets/FSkinProp.java @@ -397,6 +397,7 @@ public enum FSkinProp { IMG_ABILITY_DOUBLE_STRIKE (new int[] {166, 2, 80, 80}, PropType.ABILITY), IMG_ABILITY_FIRST_STRIKE (new int[] {248, 2, 80, 80}, PropType.ABILITY), IMG_ABILITY_FEAR (new int[] {84, 412, 80, 80}, PropType.ABILITY), + IMG_ABILITY_FLASH (new int[] {166, 576, 80, 80}, PropType.ABILITY), IMG_ABILITY_FLYING (new int[] {330, 2, 80, 80}, PropType.ABILITY), IMG_ABILITY_HASTE (new int[] {412, 494, 80, 80}, PropType.ABILITY), IMG_ABILITY_HEXPROOF (new int[] {412, 2, 80, 80}, PropType.ABILITY),