diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index 6396671268c..8d5d7af1f83 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -707,7 +707,7 @@ public class GameAction { // needed for ETB lookahead like Bronzehide Lion stAb.putParam("AffectedZone", "All"); SpellAbilityEffect.addForgetOnMovedTrigger(eff, "Battlefield"); - game.getAction().moveToCommand(eff, cause); + eff.getOwner().getZone(ZoneType.Command).add(eff); } eff.addRemembered(copied); @@ -1112,6 +1112,10 @@ public class GameAction { // search for cards with static abilities final FCollection staticAbilities = new FCollection<>(); final CardCollection staticList = new CardCollection(); + Table> dependencies = null; + if (preList.isEmpty()) { + dependencies = HashBasedTable.create(); + } game.forEachCardInGame(new Visitor() { @Override @@ -1146,7 +1150,7 @@ public class GameAction { StaticAbility stAb = staticsForLayer.get(0); // dependency with CDA seems unlikely if (!stAb.isCharacteristicDefining()) { - stAb = findStaticAbilityToApply(layer, staticsForLayer, preList, affectedPerAbility); + stAb = findStaticAbilityToApply(layer, staticsForLayer, preList, affectedPerAbility, dependencies); } staticsForLayer.remove(stAb); final CardCollectionView previouslyAffected = affectedPerAbility.get(stAb); @@ -1233,6 +1237,8 @@ public class GameAction { game.getTriggerHandler().runTrigger(TriggerType.Always, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Immediate, runParams, false); + + game.getView().setDependencies(dependencies); } // Update P/T and type in the view only once after all the cards have been processed, to avoid flickering @@ -1251,7 +1257,8 @@ public class GameAction { game.getTracker().unfreeze(); } - private StaticAbility findStaticAbilityToApply(StaticAbilityLayer layer, List staticsForLayer, CardCollectionView preList, Map affectedPerAbility) { + private StaticAbility findStaticAbilityToApply(StaticAbilityLayer layer, List staticsForLayer, CardCollectionView preList, Map affectedPerAbility, + Table> dependencies) { if (staticsForLayer.size() == 1) { return staticsForLayer.get(0); } @@ -1309,6 +1316,13 @@ public class GameAction { if (dependency) { dependencyGraph.addVertex(otherStAb); dependencyGraph.addEdge(stAb, otherStAb); + if (dependencies != null) { + if (dependencies.contains(stAb, otherStAb)) { + dependencies.get(stAb, otherStAb).add(layer); + } else { + dependencies.put(stAb, otherStAb, EnumSet.of(layer)); + } + } } // undo changes and check next pair diff --git a/forge-game/src/main/java/forge/game/GameView.java b/forge-game/src/main/java/forge/game/GameView.java index 10e0da7a76b..2c5540db3dd 100644 --- a/forge-game/src/main/java/forge/game/GameView.java +++ b/forge-game/src/main/java/forge/game/GameView.java @@ -1,8 +1,12 @@ package forge.game; import java.util.List; +import java.util.Set; import com.google.common.collect.Iterables; +import com.google.common.collect.Table; +import com.google.common.collect.Table.Cell; + import forge.LobbyPlayer; import forge.deck.Deck; import forge.game.GameOutcome.AnteResult; @@ -16,6 +20,8 @@ import forge.game.phase.PhaseType; import forge.game.player.PlayerView; import forge.game.player.RegisteredPlayer; import forge.game.spellability.StackItemView; +import forge.game.staticability.StaticAbility; +import forge.game.staticability.StaticAbilityLayer; import forge.game.zone.MagicStack; import forge.trackable.TrackableCollection; import forge.trackable.TrackableObject; @@ -200,15 +206,36 @@ public class GameView extends TrackableObject { public TrackableCollection getRevealedCollection() { return get(TrackableProperty.RevealedCardsCollection); } - public void updateRevealedCards(TrackableCollection collection) { set(TrackableProperty.RevealedCardsCollection, collection); } + public String getDependencies() { + return get(TrackableProperty.Dependencies); + } + public void setDependencies(Table> dependencies) { + if (dependencies.isEmpty()) { + return; + } + StringBuilder sb = new StringBuilder(); + StaticAbilityLayer layer = null; + for (StaticAbilityLayer sal : StaticAbilityLayer.CONTINUOUS_LAYERS_WITH_DEPENDENCY) { + for (Cell> dep : dependencies.cellSet()) { + if (dep.getValue().contains(sal)) { + if (layer != sal) { + layer = sal; + sb.append("Layer " + layer.num).append(": "); + } + sb.append(dep.getColumnKey().getHostCard().toString()).append(" <- ").append(dep.getRowKey().getHostCard().toString()).append("\n"); + } + } + } + set(TrackableProperty.Dependencies, sb.toString()); + } + public CombatView getCombat() { return get(TrackableProperty.CombatView); } - public void updateCombatView(CombatView combatView) { set(TrackableProperty.CombatView, combatView); } diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityLayer.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityLayer.java index 83f762bdac4..1e563a50c41 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityLayer.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityLayer.java @@ -3,35 +3,44 @@ package forge.game.staticability; import com.google.common.collect.ImmutableList; public enum StaticAbilityLayer { - /** Layer 1 for control-changing effects. */ - COPY, + /** Layer 1 for copiable values. */ + COPY("1"), /** Layer 2 for control-changing effects. */ - CONTROL, + CONTROL("2"), /** Layer 3 for text-changing effects. */ - TEXT, + TEXT("3"), /** Layer 4 for type-changing effects. */ - TYPE, + TYPE("4"), /** Layer 5 for color-changing effects. */ - COLOR, + COLOR("5"), /** Layer 6 for ability effects. */ - ABILITIES, + ABILITIES("6"), /** Layer 7a for characteristic-defining power/toughness effects. */ - CHARACTERISTIC, + CHARACTERISTIC("7a"), /** Layer 7b for power- and/or toughness-setting effects. */ - SETPT, + SETPT("7b"), /** Layer 7c for power- and/or toughness-modifying effects. */ - MODIFYPT, + MODIFYPT("7c"), + + /** Layer 7d for power- and/or toughness-switching effects. */ + //SWITCHPT("7d"), /** Layer for game rule-changing effects. */ - RULES; + RULES("8"); + + public final String num; + + StaticAbilityLayer(String n) { + num = n; + } public final static ImmutableList CONTINUOUS_LAYERS = ImmutableList.of(COPY, CONTROL, TEXT, TYPE, COLOR, ABILITIES, CHARACTERISTIC, SETPT, MODIFYPT, RULES); diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index f8a46ab428e..3d2515abc0a 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -301,7 +301,8 @@ public enum TrackableProperty { GameLog(TrackableTypes.StringType), NeedsPhaseRedrawn(TrackableTypes.BooleanType), PlayerTurn(TrackableTypes.PlayerViewType, FreezeMode.IgnoresFreeze), - Phase(TrackableTypes.EnumType(PhaseType.class), FreezeMode.IgnoresFreeze); + Phase(TrackableTypes.EnumType(PhaseType.class), FreezeMode.IgnoresFreeze), + Dependencies(TrackableTypes.StringType); public enum FreezeMode { IgnoresFreeze, diff --git a/forge-gui-desktop/src/main/java/forge/gui/framework/EDocID.java b/forge-gui-desktop/src/main/java/forge/gui/framework/EDocID.java index 607b77a0b49..3fd274cd0be 100644 --- a/forge-gui-desktop/src/main/java/forge/gui/framework/EDocID.java +++ b/forge-gui-desktop/src/main/java/forge/gui/framework/EDocID.java @@ -87,6 +87,7 @@ public enum EDocID { REPORT_MESSAGE (), REPORT_STACK (), REPORT_COMBAT (), + REPORT_DEPENDENCIES (), REPORT_LOG (), DEV_MODE (), diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java index 92f77001077..b1f5006f0bd 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java @@ -104,6 +104,7 @@ import forge.player.PlayerZoneUpdate; import forge.player.PlayerZoneUpdates; import forge.screens.match.controllers.CAntes; import forge.screens.match.controllers.CCombat; +import forge.screens.match.controllers.CDependencies; import forge.screens.match.controllers.CDetailPicture; import forge.screens.match.controllers.CDev; import forge.screens.match.controllers.CDock; @@ -167,6 +168,7 @@ public final class CMatchUI private final CAntes cAntes = new CAntes(this); private final CCombat cCombat = new CCombat(); + private final CDependencies cDependencies = new CDependencies(this); private final CDetailPicture cDetailPicture = new CDetailPicture(this); private final CDev cDev = new CDev(this); private final CDock cDock = new CDock(this); @@ -190,6 +192,7 @@ public final class CMatchUI this.myDocs.put(EDocID.REPORT_MESSAGE, getCPrompt().getView()); this.myDocs.put(EDocID.REPORT_STACK, getCStack().getView()); this.myDocs.put(EDocID.REPORT_COMBAT, cCombat.getView()); + this.myDocs.put(EDocID.REPORT_DEPENDENCIES, cDependencies.getView()); this.myDocs.put(EDocID.REPORT_LOG, cLog.getView()); this.myDocs.put(EDocID.DEV_MODE, getCDev().getView()); this.myDocs.put(EDocID.BUTTON_DOCK, getCDock().getView()); @@ -410,6 +413,11 @@ public final class CMatchUI cCombat.update(); } // showCombat(CombatView) + @Override + public void updateDependencies() { + cDependencies.update(); + } + @Override public void updateDayTime(String daytime) { super.updateDayTime(daytime); diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CDependencies.java b/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CDependencies.java new file mode 100644 index 00000000000..e40b75fd81e --- /dev/null +++ b/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CDependencies.java @@ -0,0 +1,51 @@ +package forge.screens.match.controllers; + +import forge.game.GameView; +import forge.gui.framework.ICDoc; +import forge.screens.match.CMatchUI; +import forge.screens.match.views.VDependencies; + +/** + * Controls the combat panel in the match UI. + * + *

(C at beginning of class name denotes a control class.) + * + */ +public class CDependencies implements ICDoc { + + private final CMatchUI matchUI; + private final VDependencies view; + public CDependencies(CMatchUI cMatchUI) { + view = new VDependencies(this); + matchUI = cMatchUI; + } + + public VDependencies getView() { + return view; + } + + @Override + public void register() { + } + + /* (non-Javadoc) + * @see forge.gui.framework.ICDoc#initialize() + */ + @Override + public void initialize() { + } + + /* (non-Javadoc) + * @see forge.gui.framework.ICDoc#update() + */ + @Override + public void update() { + GameView game = matchUI.getGameView(); + if (game == null || game.getDependencies() == null) { + return; + } + String dependencies = game.getDependencies(); + view.updateDependencies(dependencies.lines().count(), dependencies); + } + +} diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/views/VDependencies.java b/forge-gui-desktop/src/main/java/forge/screens/match/views/VDependencies.java new file mode 100644 index 00000000000..ce62c8f7aef --- /dev/null +++ b/forge-gui-desktop/src/main/java/forge/screens/match/views/VDependencies.java @@ -0,0 +1,115 @@ +/* + * Forge: Play Magic: the Gathering. + * Copyright (C) 2011 Nate + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package forge.screens.match.views; + +import forge.gui.framework.DragCell; +import forge.gui.framework.DragTab; +import forge.gui.framework.EDocID; +import forge.gui.framework.IVDoc; +import forge.screens.match.controllers.CDependencies; +import forge.toolbox.FSkin; +import forge.toolbox.FSkin.SkinnedTextArea; +import forge.util.Localizer; +import net.miginfocom.swing.MigLayout; + +/** + * Assembles Swing components of layer dependencies. + * + *

(V at beginning of class name denotes a view class.) + */ +public class VDependencies implements IVDoc { + + // Fields used with interface IVDoc + private DragCell parentCell; + private final DragTab tab = new DragTab(Localizer.getInstance().getMessage("lblDependenciesTab")); + + private final SkinnedTextArea tar = new SkinnedTextArea(); + + private final CDependencies controller; + public VDependencies(final CDependencies controller) { + this.controller = controller; + tar.setOpaque(false); + tar.setBorder(new FSkin.MatteSkinBorder(0, 0, 0, 0, FSkin.getColor(FSkin.Colors.CLR_BORDERS))); + tar.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT)); + tar.setFocusable(false); + tar.setLineWrap(true); + } + + //========== Overridden methods + + /* (non-Javadoc) + * @see forge.gui.framework.IVDoc#populate() + */ + @Override + public void populate() { + parentCell.getBody().removeAll(); + parentCell.getBody().setLayout(new MigLayout("insets 0, gap 0, wrap")); + parentCell.getBody().add(tar, "w 95%!, gapleft 3%, gaptop 1%, h 95%"); + } + + /* (non-Javadoc) + * @see forge.gui.framework.IVDoc#setParentCell() + */ + @Override + public void setParentCell(final DragCell cell0) { + this.parentCell = cell0; + } + + /* (non-Javadoc) + * @see forge.gui.framework.IVDoc#getParentCell() + */ + @Override + public DragCell getParentCell() { + return this.parentCell; + } + + /* (non-Javadoc) + * @see forge.gui.framework.IVDoc#getDocumentID() + */ + @Override + public EDocID getDocumentID() { + return EDocID.REPORT_DEPENDENCIES; + } + + /* (non-Javadoc) + * @see forge.gui.framework.IVDoc#getTabLabel() + */ + @Override + public DragTab getTabLabel() { + return tab; + } + + /* (non-Javadoc) + * @see forge.gui.framework.IVDoc#getLayoutControl() + */ + @Override + public CDependencies getLayoutControl() { + return controller; + } + + //========= Observer update methods + + public void updateDependencies(final long cntDependencies, final String desc) { + tab.setText(cntDependencies > 0 ? (Localizer.getInstance().getMessage("lblDependenciesTab") + " : " + cntDependencies) : Localizer.getInstance().getMessage("lblDependenciesTab")); + + // No need to update this unless it's showing + if (parentCell == null || !this.equals(parentCell.getSelected())) { return; } + + tar.setText(desc); + } +} diff --git a/forge-gui/res/defaults/match.xml b/forge-gui/res/defaults/match.xml index a9c53dc51c0..839733ea2a8 100644 --- a/forge-gui/res/defaults/match.xml +++ b/forge-gui/res/defaults/match.xml @@ -4,6 +4,7 @@ REPORT_STACK REPORT_COMBAT REPORT_LOG + REPORT_DEPENDENCIES REPORT_MESSAGE diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties index 0f46a6f71cd..816048807ce 100644 --- a/forge-gui/res/languages/de-DE.properties +++ b/forge-gui/res/languages/de-DE.properties @@ -1105,6 +1105,7 @@ lblPlayers=Spieler lblLog=Bericht lblDev=Entw. lblCombatTab=Kampf +lblDependenciesTab=Dependencies lblStack=Stapel lblMustWaitPriority=Warte auf Priorität... #FDeckEditor.java diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index 6d51e4a8d10..9e1df788bc2 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -1118,6 +1118,7 @@ lblPlayers=Players lblLog=Log lblDev=Dev lblCombatTab=Combat +lblDependenciesTab=Dependencies lblStack=Stack lblMustWaitPriority=Must wait for priority... #FDeckEditor.java diff --git a/forge-gui/res/languages/es-ES.properties b/forge-gui/res/languages/es-ES.properties index 8b232fd6d05..bcc88edbbac 100644 --- a/forge-gui/res/languages/es-ES.properties +++ b/forge-gui/res/languages/es-ES.properties @@ -1111,6 +1111,7 @@ lblPlayers=Jugadores lblLog=Log lblDev=Dev lblCombatTab=Combate +lblDependenciesTab=Dependencies lblStack=Pila lblMustWaitPriority=Debes esperar debido a la prioridad... #FDeckEditor.java diff --git a/forge-gui/res/languages/fr-FR.properties b/forge-gui/res/languages/fr-FR.properties index c4845bb341b..9e1ad3ce337 100644 --- a/forge-gui/res/languages/fr-FR.properties +++ b/forge-gui/res/languages/fr-FR.properties @@ -1109,6 +1109,7 @@ lblPlayers=Joueurs lblLog=Journal lblDev=Dev lblCombatTab=Combat +lblDependenciesTab=Dependencies lblStack=Empiler lblMustWaitPriority=Doit attendre la priorité... #FDeckEditor.java diff --git a/forge-gui/res/languages/it-IT.properties b/forge-gui/res/languages/it-IT.properties index 3cd6138d55b..136f51b1b33 100644 --- a/forge-gui/res/languages/it-IT.properties +++ b/forge-gui/res/languages/it-IT.properties @@ -1106,6 +1106,7 @@ lblPlayers=Giocatori lblLog=Registro lblDev=Sviluppo lblCombatTab=Combattimento +lblDependenciesTab=Dependencies lblStack=Pila lblMustWaitPriority=Devi aspettare la priorità ... #FDeckEditor.java diff --git a/forge-gui/res/languages/ja-JP.properties b/forge-gui/res/languages/ja-JP.properties index 7a3d0ed01e5..694baf9b490 100644 --- a/forge-gui/res/languages/ja-JP.properties +++ b/forge-gui/res/languages/ja-JP.properties @@ -1108,6 +1108,7 @@ lblPlayers=プレイヤー lblLog=ログ lblDev=開発者 lblCombatTab=戦闘 +lblDependenciesTab=Dependencies lblStack=スタック lblMustWaitPriority=優先権を待つ必要があります... #FDeckEditor.java diff --git a/forge-gui/res/languages/pt-BR.properties b/forge-gui/res/languages/pt-BR.properties index bb48930542a..80656f4e66c 100644 --- a/forge-gui/res/languages/pt-BR.properties +++ b/forge-gui/res/languages/pt-BR.properties @@ -1133,6 +1133,7 @@ lblPlayers=Jogadores lblLog=Registros lblDev=Desenv. lblCombatTab=Batalha +lblDependenciesTab=Dependencies lblStack=Pilha lblMustWaitPriority=Deve esperar pela prioridade... #FDeckEditor.java diff --git a/forge-gui/res/languages/zh-CN.properties b/forge-gui/res/languages/zh-CN.properties index da204ec94ac..9c4d191b06e 100644 --- a/forge-gui/res/languages/zh-CN.properties +++ b/forge-gui/res/languages/zh-CN.properties @@ -1112,6 +1112,7 @@ lblPlayers=玩家列表 lblLog=日志 lblDev=开发者工具 lblCombatTab=战斗 +lblDependenciesTab=Dependencies lblStack=堆叠 lblMustWaitPriority=等待获得优先权 #FDeckEditor.java diff --git a/forge-gui/src/main/java/forge/gamemodes/match/AbstractGuiGame.java b/forge-gui/src/main/java/forge/gamemodes/match/AbstractGuiGame.java index 7fe815a1ad6..2062150429e 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/AbstractGuiGame.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/AbstractGuiGame.java @@ -846,5 +846,8 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards { } daytime = null; } + + public void updateDependencies() { + } // End of Choice code } diff --git a/forge-gui/src/main/java/forge/gui/control/FControlGameEventHandler.java b/forge-gui/src/main/java/forge/gui/control/FControlGameEventHandler.java index 82ada7213b5..6d949a18f49 100644 --- a/forge-gui/src/main/java/forge/gui/control/FControlGameEventHandler.java +++ b/forge-gui/src/main/java/forge/gui/control/FControlGameEventHandler.java @@ -203,6 +203,7 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base { @Override public Void visit(final GameEventPlayerPriority event) { needCombatUpdate = true; + matchController.updateDependencies(); return processEvent(); } diff --git a/forge-gui/src/main/java/forge/gui/interfaces/IGuiGame.java b/forge-gui/src/main/java/forge/gui/interfaces/IGuiGame.java index b95c2974f9f..d05fd621644 100644 --- a/forge-gui/src/main/java/forge/gui/interfaces/IGuiGame.java +++ b/forge-gui/src/main/java/forge/gui/interfaces/IGuiGame.java @@ -105,6 +105,8 @@ public interface IGuiGame { void updateLives(Iterable livesUpdate); void updateShards(Iterable shardsUpdate); + void updateDependencies(); + void setPanelSelection(CardView hostCard); SpellAbilityView getAbilityToPlay(CardView hostCard, List abilities, ITriggerEvent triggerEvent);