// // DiceRoller.java // package com.restlesswarrior.dnd; import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import javax.swing.*; public class DiceRoller extends JFrame implements ActionListener { private static final int HIST_WIDTH = 300; private static final int HIST_HEIGHT = 108; private static final int[] PRESET_NUM = {1, 1, 1, 1, 1, 1, 1, 3, 5, 10}; private static final int[] PRESET_NDX = {3, 5, 7, 8, 9, 11, 14, 5, 5, 5}; private static final int PRESET_ROWS = 2; private SpinnerNumberModel model; private JComboBox box; private JButton roll, ace; private JTextField total, best, most; private JLabel histLabel; private ImageIcon histogram; private boolean d1roll; private int numAces; private int aceTotal; public DiceRoller() { super("Dice Roller"); setResizable(false); JPanel pane = new JPanel(); pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS)); setContentPane(pane); JPanel top = new JPanel(); top.setLayout(new BoxLayout(top, BoxLayout.X_AXIS)); JPanel left = new JPanel(); left.setLayout(new BoxLayout(left, BoxLayout.Y_AXIS)); JPanel left1 = new JPanel(); left1.setLayout(new BoxLayout(left1, BoxLayout.X_AXIS)); model = new SpinnerNumberModel(1, 1, 999, 1); JSpinner spinner = new JSpinner(model); spinner.setMaximumSize(spinner.getPreferredSize()); left1.add(spinner); box = new JComboBox(new String[] { "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d10", "d12", "d16", "d20", "d24", "d30", "d100" }); box.setSelectedIndex(5); // default to d6 box.addActionListener(this); box.setMaximumSize(box.getPreferredSize()); left1.add(box); left.add(left1); JPanel left2 = new JPanel(); left2.setLayout(new BoxLayout(left2, BoxLayout.X_AXIS)); roll = new JButton("Roll"); roll.setMnemonic('r'); roll.addActionListener(this); left2.add(roll); ace = new JButton("Ace"); ace.setMnemonic('a'); ace.addActionListener(this); ace.setEnabled(false); left2.add(ace); left.add(left2); JPanel left3 = new JPanel(); left3.setLayout(new BoxLayout(left3, BoxLayout.X_AXIS)); JLabel totalLabel = new JLabel("Total: "); totalLabel.setDisplayedMnemonic('t'); left3.add(Box.createHorizontalGlue()); left3.add(new JLabel("Total: ")); total = new JTextField(8); total.setEditable(false); total.setMaximumSize(total.getPreferredSize()); totalLabel.setLabelFor(total); left3.add(total); left.add(left3); JPanel left4 = new JPanel(); left4.setLayout(new BoxLayout(left4, BoxLayout.X_AXIS)); JLabel bestLabel = new JLabel("Best: "); bestLabel.setDisplayedMnemonic('b'); left4.add(Box.createHorizontalGlue()); left4.add(bestLabel); best = new JTextField(8); best.setEditable(false); best.setMaximumSize(best.getPreferredSize()); bestLabel.setLabelFor(best); left4.add(best); left.add(left4); JPanel left5 = new JPanel(); left5.setLayout(new BoxLayout(left5, BoxLayout.X_AXIS)); JLabel mostLabel = new JLabel("Most: "); mostLabel.setDisplayedMnemonic('m'); left5.add(Box.createHorizontalGlue()); left5.add(mostLabel); most = new JTextField(8); most.setEditable(false); most.setMaximumSize(most.getPreferredSize()); mostLabel.setLabelFor(most); left5.add(most); left.add(left5); top.add(left); // create starting histogram image, with some documentation BufferedImage startImage = new BufferedImage( HIST_WIDTH + 2, HIST_HEIGHT + 2, BufferedImage.TYPE_INT_RGB); Graphics g = startImage.getGraphics(); g.setColor(Color.green); g.setFont(new Font("Serif", Font.BOLD, 20)); g.drawString("Dice Roller by Restless Warrior", 15, 24); g.setColor(Color.yellow); g.setFont(new Font("SansSerif", Font.PLAIN, 12)); g.drawString("\"Best\" is highest value with # of times rolled.", 24, 46); g.drawString("\"Botch\" reported if more than 50% are 1s.", 24, 60); g.drawString("\"Ace\" rerolls maximal values from previous roll.", 24, 74); g.drawString("\"Ace\" keeps track of total maximum in brackets.", 24, 88); g.dispose(); histogram = new ImageIcon(startImage); histLabel = new JLabel(histogram); top.add(histLabel); pane.add(top); // create preset roll combination buttons along the bottom rows int len = PRESET_NUM.length; int cols = len / PRESET_ROWS; if (len % PRESET_ROWS > 0) cols++; int digits = ("" + len).length(); JPanel presets = null; for (int i=0; i high) { count = 1; high = rolls[i]; } else if (rolls[i] == high) count++; } boolean botch = false; String s = "" + high + "x" + count; if (aceTotal > 0) s += " [" + (aceTotal + high) + "]"; else if (ones > rolls.length / 2) { s += " [botch]"; botch = true; } numAces = high == die ? count : 0; if (numAces > 0 && !botch) ace.setEnabled(true); else { ace.setEnabled(false); aceTotal = 0; } best.setText(s); } public void doHistogram(int[] rolls, int xlen) { int[] hist = new int[xlen]; for (int i=0; i ylen) { ylen = hist[i]; ycount = 1; yvals[0] = i + 1; } else if (hist[i] == ylen) yvals[ycount++] = i + 1; } String s = ycount > 1 ? "(" : ""; for (int i=0; i 1) s += ")"; most.setText(s + "x" + ylen); // draw histogram int xinc = HIST_WIDTH / xlen; int yinc = HIST_HEIGHT / ylen; BufferedImage image = new BufferedImage( HIST_WIDTH + 2, HIST_HEIGHT + 2, BufferedImage.TYPE_INT_RGB); if (xinc >= 1 && yinc >= 1) { int ymax = HIST_HEIGHT / yinc; Graphics2D g = image.createGraphics(); for (int i=0; i= 0) doPreset(i); } } public int getDie() { String s = ((String) box.getSelectedItem()).substring(1); return Integer.parseInt(s); } public static void main(String[] args) { DiceRoller dr = new DiceRoller(); dr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); dr.pack(); Dimension siz = dr.getSize(); Dimension scr = Toolkit.getDefaultToolkit().getScreenSize(); dr.setLocation((scr.width - siz.width) / 2, (scr.height - siz.height) / 2); dr.show(); } }