package puzzledice; import gui.AreaEditPanel; import gui.PuzzleEditPanel; import gui.WindowMain; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.swing.BoxLayout; import javax.swing.DefaultComboBoxModel; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; import com.mxgraph.model.mxCell; import com.mxgraph.view.mxGraph; public class DoorUnlockBlock extends PuzzleBlock { private AreaBlock _sourceArea, _destArea; private PuzzleBlock _keyBlock; private static int nextIndex = 0; public static void reset() { nextIndex = 0; } private String _sourceAreaName, _destAreaName, _keyName; public void setSourceAreaName(String value) { _sourceAreaName = value; } public void setDestAreaName(String value) { _destAreaName = value; } public void setKeyName(String value) { _keyName = value; } private JComboBox _sourceAreaSelect, _destAreaSelect, _keySelect; // So we can actually reference ourself inside actionlisteners private DoorUnlockBlock _selfReference; public DoorUnlockBlock() { _selfReference = this; _name = "Door-Unlock-Puzzle-" + ++nextIndex; _type = "Door Unlock Puzzle"; JPanel editPanel = new JPanel(); editPanel.setLayout(new BoxLayout(editPanel, BoxLayout.Y_AXIS)); // Key Select Panel JPanel keyPanel = new JPanel(); keyPanel.setLayout(new BoxLayout(keyPanel, BoxLayout.X_AXIS)); JLabel keyLabel = new JLabel("Key Spawn:"); keyPanel.add(keyLabel); _keySelect = new JComboBox(); _keySelect.setMaximumSize(new Dimension(Integer.MAX_VALUE, _keySelect.getPreferredSize().height)); keyPanel.add(_keySelect); editPanel.add(keyPanel); // Source Area Select Panel JPanel sourceAreaPanel = new JPanel(); sourceAreaPanel.setLayout(new BoxLayout(sourceAreaPanel, BoxLayout.X_AXIS)); JLabel sourceAreaLabel = new JLabel("Door Spawn Area:"); sourceAreaPanel.add(sourceAreaLabel); _sourceAreaSelect = new JComboBox(); _sourceAreaSelect.setMaximumSize(new Dimension(Integer.MAX_VALUE, _sourceAreaSelect.getPreferredSize().height)); sourceAreaPanel.add(_sourceAreaSelect); editPanel.add(sourceAreaPanel); // Destination Area Select Panel JPanel destAreaPanel = new JPanel(); destAreaPanel.setLayout(new BoxLayout(destAreaPanel, BoxLayout.X_AXIS)); JLabel destAreaLabel = new JLabel("Destination Area:"); destAreaPanel.add(destAreaLabel); _destAreaSelect = new JComboBox(); _destAreaSelect.setMaximumSize(new Dimension(Integer.MAX_VALUE, _destAreaSelect.getPreferredSize().height)); destAreaPanel.add(_destAreaSelect); editPanel.add(destAreaPanel); _editUI = editPanel; _keySelect.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { if(_keyBlock == _keySelect.getSelectedItem() || _keyBlock == null && _keySelect.getSelectedItem().equals("None")) return; mxGraph puzzleGraph = WindowMain.getPuzzleGraph(); // Before anything, check for a cycle if (_keySelect.getSelectedItem() != null && !_keySelect.getSelectedItem().equals("None")) { PuzzleBlock block = (PuzzleBlock)_keySelect.getSelectedItem(); if (block.canReachBlockBackwards(DoorUnlockBlock.this)) { SwingUtilities.invokeLater(new Runnable() { public void run() { JOptionPane.showMessageDialog(null, "Error: Cannot add cycle to puzzle graph."); } }); if (_keyBlock != null) _keySelect.setSelectedItem(_keyBlock); else _keySelect.setSelectedIndex(0); return; } } // first, see if we need to remove a previous edge if(_keyBlock != null) { puzzleGraph.getModel().beginUpdate(); try { puzzleGraph.removeCells(puzzleGraph.getEdgesBetween(_keyBlock.getGraphCell(), _graphCell, false)); } finally { puzzleGraph.getModel().endUpdate(); } } if (_keySelect.getSelectedItem() == null) _keySelect.setSelectedIndex(0); if(_keySelect.getSelectedItem().equals("None")) _keyBlock = null; else { _keyBlock = (PuzzleBlock)_keySelect.getSelectedItem(); // update the graph with a new edge puzzleGraph.getModel().beginUpdate(); try { puzzleGraph.insertEdge(puzzleGraph.getDefaultParent(), null, null, _keyBlock.getGraphCell(), _graphCell);} finally { puzzleGraph.getModel().endUpdate();} } PuzzleEditPanel.resetTextualDescription(); WindowMain.updatePuzzleGraph(); } }); _sourceAreaSelect.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { if(_sourceArea == _sourceAreaSelect.getSelectedItem() || _sourceArea == null && _sourceAreaSelect.getSelectedItem().equals("None")) return; mxGraph puzzleGraph = WindowMain.getPuzzleGraph(); // Before anything, check for a cycle if (_sourceAreaSelect.getSelectedItem() != null && !_sourceAreaSelect.getSelectedItem().equals("None")) { AreaBlock block = (AreaBlock)_sourceAreaSelect.getSelectedItem(); if (block.canReachBlockBackwards(DoorUnlockBlock.this)) { SwingUtilities.invokeLater(new Runnable() { public void run() { JOptionPane.showMessageDialog(null, "Error: Cannot add cycle to puzzle graph."); } }); if (_sourceArea != null) _sourceAreaSelect.setSelectedItem(_sourceArea); else _sourceAreaSelect.setSelectedIndex(0); return; } } // First, see if we need to remove a previous edge if(_sourceArea != null) { _sourceArea.removeSourceLock(_selfReference); puzzleGraph.getModel().beginUpdate(); try { puzzleGraph.removeCells(puzzleGraph.getEdgesBetween(_sourceArea.getPuzzleGraphCell(), _graphCell, false)); _sourceArea.maybeDeletePuzzleCell(); } finally { puzzleGraph.getModel().endUpdate();} } if (_sourceAreaSelect.getSelectedItem() == null) _sourceAreaSelect.setSelectedIndex(0); if(_sourceAreaSelect.getSelectedItem().equals("None")) _sourceArea = null; else { _sourceArea = (AreaBlock)_sourceAreaSelect.getSelectedItem(); _sourceArea.addSourceLock(_selfReference); // update the graph with a new edge puzzleGraph.getModel().beginUpdate(); try { if(_sourceArea.getPuzzleGraphCell() == null) { _sourceArea.setPuzzleGraphCell(puzzleGraph.insertVertex(puzzleGraph.getDefaultParent(), null, _sourceArea, 0, 0, 0, 0, null)); mxCell edge = (mxCell)puzzleGraph.insertEdge(puzzleGraph.getDefaultParent(), null, null, WindowMain.getHierarchyRoot(), _sourceArea.getPuzzleGraphCell()); edge.setVisible(false); puzzleGraph.updateCellSize(_sourceArea.getPuzzleGraphCell()); } puzzleGraph.insertEdge(puzzleGraph.getDefaultParent(), null, null, _sourceArea.getPuzzleGraphCell(), _graphCell); } finally {puzzleGraph.getModel().endUpdate();} } // Update the other list _destAreaSelect.setModel(new DefaultComboBoxModel(makeDestAreaList())); if(_destArea == null) _destAreaSelect.setSelectedIndex(0); else _destAreaSelect.setSelectedItem(_destArea); PuzzleEditPanel.resetTextualDescription(); WindowMain.updatePuzzleGraph(); } }); _destAreaSelect.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { if(_destArea == _destAreaSelect.getSelectedItem() || _destArea == null && _destAreaSelect.getSelectedItem().equals("None")) return; mxGraph puzzleGraph = WindowMain.getPuzzleGraph(); // Before anything, check for a cycle if (_destAreaSelect.getSelectedItem() != null && !_destAreaSelect.getSelectedItem().equals("None")) { AreaBlock block = (AreaBlock)_destAreaSelect.getSelectedItem(); if (DoorUnlockBlock.this.canReachBlockBackwards(block)) { SwingUtilities.invokeLater(new Runnable() { public void run() { JOptionPane.showMessageDialog(null, "Error: Cannot add cycle to puzzle graph."); } }); if (_destArea != null) _destAreaSelect.setSelectedItem(_destArea); else _destAreaSelect.setSelectedIndex(0); return; } } // First, see if we need to remove a previous edge if(_destArea != null) { _destArea.removeDoorLock(_selfReference); puzzleGraph.getModel().beginUpdate(); try { puzzleGraph.removeCells(puzzleGraph.getEdgesBetween(_destArea.getPuzzleGraphCell(), _graphCell, false)); _destArea.maybeDeletePuzzleCell(); } finally { puzzleGraph.getModel().endUpdate();} } if (_destAreaSelect.getSelectedItem() == null) _destAreaSelect.setSelectedIndex(0); if(_destAreaSelect.getSelectedItem().equals("None")) _destArea = null; else { _destArea = (AreaBlock)_destAreaSelect.getSelectedItem(); _destArea.addDoorLock(_selfReference); // update the graph with a new edge puzzleGraph.getModel().beginUpdate(); try { if(_destArea.getPuzzleGraphCell() == null) { _destArea.setPuzzleGraphCell(puzzleGraph.insertVertex(puzzleGraph.getDefaultParent(), null, _destArea, 0, 0, 0, 0, null)); mxCell edge = (mxCell)puzzleGraph.insertEdge(puzzleGraph.getDefaultParent(), null, null, WindowMain.getHierarchyRoot(), _destArea.getPuzzleGraphCell()); edge.setVisible(false); puzzleGraph.updateCellSize(_destArea.getPuzzleGraphCell()); } puzzleGraph.insertEdge(puzzleGraph.getDefaultParent(), null, null, _graphCell, _destArea.getPuzzleGraphCell()); } finally {puzzleGraph.getModel().endUpdate();} } // Update the other list _sourceAreaSelect.setModel(new DefaultComboBoxModel(makeSourceAreaList())); if(_sourceArea == null) _sourceAreaSelect.setSelectedIndex(0); else _sourceAreaSelect.setSelectedItem(_sourceArea); PuzzleEditPanel.resetTextualDescription(); WindowMain.updatePuzzleGraph(); } }); } @Override public void update() { _keySelect.setModel(new DefaultComboBoxModel(makeKeyList())); if (_keyBlock == null) _keySelect.setSelectedIndex(0); else _keySelect.setSelectedItem(_keyBlock); _sourceAreaSelect.setModel(new DefaultComboBoxModel(makeSourceAreaList())); if(_sourceArea == null) _sourceAreaSelect.setSelectedIndex(0); else _sourceAreaSelect.setSelectedItem(_sourceArea); _destAreaSelect.setModel(new DefaultComboBoxModel(makeDestAreaList())); if(_destArea == null) _destAreaSelect.setSelectedIndex(0); else _destAreaSelect.setSelectedItem(_destArea); } private Object[] makeKeyList() { List<Object> retVal = new ArrayList<Object>(); PuzzleBlock[] blockList = PuzzleEditPanel.getBlockList(); retVal.add("None"); for(PuzzleBlock p : blockList) { if(!p.equals(this)) retVal.add(p); } return retVal.toArray(); } private Object[] makeSourceAreaList() { List<Object> retVal = new ArrayList<Object>(); AreaBlock[] areaList = AreaEditPanel.getAreaList(); retVal.add("None"); for(AreaBlock a : areaList) { if(!a.equals(_destAreaSelect.getSelectedItem())) retVal.add(a); } return retVal.toArray(); } private Object[] makeDestAreaList() { List<Object> retVal = new ArrayList<Object>(); AreaBlock[] areaList = AreaEditPanel.getAreaList(); retVal.add("None"); for(AreaBlock a : areaList) { if(!a.equals(_sourceAreaSelect.getSelectedItem())) retVal.add(a); } return retVal.toArray(); } @Override public void maybeRemoveRef(PuzzleBlock block) { if (block.equals(_keyBlock)) { _keyBlock = null; _keySelect.setSelectedIndex(0); } } @Override public void onDelete() { // Remove our reference to our source and dest areas mxGraph puzzleGraph = WindowMain.getPuzzleGraph(); if(_sourceArea != null) { _sourceArea.removeSourceLock(this); puzzleGraph.getModel().beginUpdate(); try { puzzleGraph.removeCells(puzzleGraph.getEdgesBetween(_sourceArea.getPuzzleGraphCell(), _graphCell, false)); _sourceArea.maybeDeletePuzzleCell(); } finally { puzzleGraph.getModel().endUpdate();} } if(_destArea != null) { _destArea.removeDoorLock(this); puzzleGraph.getModel().beginUpdate(); try { puzzleGraph.removeCells(puzzleGraph.getEdgesBetween(_destArea.getPuzzleGraphCell(), _graphCell, false)); _destArea.maybeDeletePuzzleCell(); } finally { puzzleGraph.getModel().endUpdate();} } } // For when the changing area topology creates a cycle with this door unlock. // Need to break the source edges to fix the cycle public void disconnectSource() { mxGraph puzzleGraph = WindowMain.getPuzzleGraph(); if (_sourceArea != null) { _sourceArea.removeSourceLock(this); puzzleGraph.getModel().beginUpdate(); try { puzzleGraph.removeCells(puzzleGraph.getEdgesBetween(_sourceArea.getPuzzleGraphCell(), _graphCell, false)); } finally { puzzleGraph.getModel().endUpdate(); } _sourceArea = null; _sourceAreaSelect.setSelectedIndex(0); } if (_keyBlock != null) { puzzleGraph.getModel().beginUpdate(); try { puzzleGraph.removeCells(puzzleGraph.getEdgesBetween(_keyBlock.getGraphCell(), _graphCell, false)); } finally { puzzleGraph.getModel().endUpdate(); } _keyBlock = null; _keySelect.setSelectedIndex(0); } } public AreaBlock getSourceBlock() { return _sourceArea; } public AreaBlock getDestBlock() { return _destArea; } @Override public void maybeRemoveRef(AreaBlock area) { if(area.equals(_sourceArea)) { _sourceArea = null; _sourceAreaSelect.setSelectedIndex(0); } if(area.equals(_destArea)) { _destArea = null; _destAreaSelect.setSelectedIndex(0); } } @Override public String getTextualDescription() { String retVal = ""; if (_sourceArea != null) retVal += _sourceArea.getTextualDescription(); if(_keyBlock != null) retVal += _keyBlock.getTextualDescription(); String sourceArea = (_sourceArea == null) ? "SOMEWHERE" : _sourceArea.getName(); String destArea = (_destArea == null) ? "SOMEWHERE" : _destArea.getName(); String key = (_keyBlock == null) ? "SOMETHING" : _keyBlock.getOutputTempName(); retVal += "The player uses " + key + " to unlock the door from " + sourceArea + " to " + destArea + ". "; return retVal; } @Override public void attachBlocksToName(Map<String, AreaBlock> areas, Map<String, PuzzleBlock> puzzles) { mxGraph puzzleGraph = WindowMain.getPuzzleGraph(); if (_sourceAreaName != null) { _sourceArea = areas.get(_sourceAreaName); _sourceArea.addSourceLock(_selfReference); puzzleGraph.getModel().beginUpdate(); try { if(_sourceArea.getPuzzleGraphCell() == null) { _sourceArea.setPuzzleGraphCell(puzzleGraph.insertVertex(puzzleGraph.getDefaultParent(), null, _sourceArea, 0, 0, 0, 0, null)); mxCell edge = (mxCell)puzzleGraph.insertEdge(puzzleGraph.getDefaultParent(), null, null, WindowMain.getHierarchyRoot(), _sourceArea.getPuzzleGraphCell()); edge.setVisible(false); puzzleGraph.updateCellSize(_sourceArea.getPuzzleGraphCell()); } puzzleGraph.insertEdge(puzzleGraph.getDefaultParent(), null, null, _sourceArea.getPuzzleGraphCell(), _graphCell); } finally {puzzleGraph.getModel().endUpdate();} } if (_destAreaName != null) { _destArea = areas.get(_destAreaName); _destArea.addDoorLock(_selfReference); // update the graph with a new edge puzzleGraph.getModel().beginUpdate(); try { if(_destArea.getPuzzleGraphCell() == null) { _destArea.setPuzzleGraphCell(puzzleGraph.insertVertex(puzzleGraph.getDefaultParent(), null, _destArea, 0, 0, 0, 0, null)); mxCell edge = (mxCell)puzzleGraph.insertEdge(puzzleGraph.getDefaultParent(), null, null, WindowMain.getHierarchyRoot(), _destArea.getPuzzleGraphCell()); edge.setVisible(false); puzzleGraph.updateCellSize(_destArea.getPuzzleGraphCell()); } puzzleGraph.insertEdge(puzzleGraph.getDefaultParent(), null, null, _graphCell, _destArea.getPuzzleGraphCell()); } finally {puzzleGraph.getModel().endUpdate();} } if (_keyName != null) { _keyBlock = puzzles.get(_keyName); puzzleGraph.getModel().beginUpdate(); try { puzzleGraph.insertEdge(puzzleGraph.getDefaultParent(), null, null, _keyBlock.getGraphCell(), _graphCell);} finally { puzzleGraph.getModel().endUpdate();} } this.update(); } @Override public PuzzleBlock[] getPuzzleInputs() { if (_keyBlock != null) return new PuzzleBlock[] { _keyBlock }; return new PuzzleBlock[0]; } @Override public AreaBlock[] getAreaInputs() { if (_sourceArea != null) return new AreaBlock[] { _sourceArea }; return new AreaBlock[0]; } @Override public String toXML() { String xml = "<DoorUnlockPuzzle name=\"" + _name + "\" "; if (_sourceArea != null) xml += "source=\"" + _sourceArea.getName() + "\" "; if (_destArea != null) xml += "dest=\"" + _destArea.getName() + "\" "; if (_keyBlock != null) xml += "key=\"" + _keyBlock.getName() + "\" "; xml += "/>"; return xml; } }