Third Edition Earthdawn Dice Roller in Java

So, I play an RPG called Earthdawn; it’s a lot like D&D, but for real nerds.

One of the things we all do in my gaming group is write our own dice rollers; rolling actual dice is SO passé–and there’s an ongoing argument about whether or not a seeded random is more or less random than the natural flaws in dice and rolling surfaces. Java is the language in which I learned to write math, so I somewhat naturally write algorithms in Java without thinking. It’s easy enough to translate this into C# or whatever.

Ok, so, here’s the algorithm. In Earthdawn, dice rolls are predicated on the step level of the difficulty. You may have an attack roll at step 18 and a damage roll at step 22. In 3rd edition Earthdawn, that translates to rolling d12+d10+d8 to attack, and 2d12+2d6 for damage. Here’s the chart (click to embiggen):

As you can see, there’s some kind of progression here; it turns out that the algorithm is a simple infinite series. There’s a jump in the number of dice every seven steps. Hence, the algorithm has a few simple steps:

(1) Divide the step number by 7.
(2) Determine and store the floor and the modulus.
(3) Roll a number of d12s equal to (floor – 1).
(4) Roll dice equal to the corresponding modulus (the first addition of dice past the 7 threshold will be 2d6, so if the modulus is 1, 2d6 are rolled and added).

That is the step algorithm such that no lookup is now necessary; Earthdawn has exploding dice and epic
fails, however, so two things are necessary. Look at the exploding dice method; if you roll the maximum value of a die, you can roll it again. You can keep rolling that die until a value shows that is less than the maximum value, such that a d6 rolled with a result of 6 can be rerolled. On the second roll, 6 results. On the third roll, 2 results, so the total value of that die roll is 14. For epic fails, if you roll more than one die and all dice show ones, you have epically failed (similar to a fumble in D&D, and with equivalent disastrous results).

Here’s my dice roller; click to embiggen:

So, here’s the code. It’s intended to be self-contained (you can see that I use a pic of Captain Malcolm Reynolds; just drop a pic in your file structure and reference it in the code if you want a background). Obviously this is bare-bones; you can adapt it at your leisure and to whatever GUI you desire. Any suggestions are welcome; I am always debugging this (and the JavaScript I’m using to display syntax highlighting is a little cranky, so forgive any indentation issues). If you can think of a way to optimize this algorithm, let me know; I always need bragging rights over the guys 😉

package dice;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;

public class ImagePanel extends JPanel implements ActionListener{

	int six = 6;
	int eight = 8;
	int ten = 10;
	int twelve = 12;
	int dice = 0; //counter for total number of dice
	public int middle; //step value entered by me.
	public boolean fail; //whether or not an epic fail happened.
	public JFrame frame;
	public Random r;
	Image img = new ImageIcon("img/MalcolmReynolds13.jpg").getImage();
	SpinnerModel stepEntry = new SpinnerNumberModel(1, 1, 300, 1);
	SpinnerModel karmaCounter = new SpinnerNumberModel(25, 0, 25, 1);
	JSpinner stepSpinner = new JSpinner(stepEntry);
	JSpinner karmaSpinner = new JSpinner(karmaCounter);
	private JTextField diceResult;
	private JButton myButton;
private JCheckBox myCheck;
	private JLabel enterStep = new JLabel("Enter Step Here.");
	public static void main(String[] args) {
		ImagePanel panel = new ImagePanel(new ImageIcon("img/MalcolmReynolds13.jpg").getImage());
		JFrame frame = new JFrame("Tarah's Dice Roller Of Awesomeness");

	public ImagePanel(String img) {
		this(new ImageIcon(img).getImage());

	public ImagePanel(Image img){
		this.img = img;
		Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
		JPanel panel = new JPanel();
		add(panel, "Center");
		myButton = new JButton("Roll The Dice.");
		diceResult = new JTextField("Roll Result", 9);
		myCheck = new JCheckBox("Use Karma.", false);
		GridLayout myGrid = new GridLayout(3, 2);

	public void paintComponent(Graphics g) {
		g.drawImage(img, 0, 0, null);
	public void actionPerformed(ActionEvent e) {
		boolean useKarma = false;
		middle = (Integer)stepSpinner.getValue();
		System.out.println("actionPerformed() thinks the step number is: " + middle);
		if (myCheck.isSelected() == true) {
			System.out.println("Using Karma.");
			useKarma = true;
			int decrease = ((Integer)karmaCounter.getValue()) - 1;
		String s = Integer.toString(rollTheDice(useKarma, middle, fail));


	//This is the Earthdawn Exploding Dice Method.
	public int d (int die){

		int sides = die;
		int result = 0;
        int roll;
		do {
			r = new Random();
            roll = r.nextInt(sides) + 1;
            result = result + roll;
            System.out.println("This is a d" + sides + " roll with result: " + result);
       } while (roll == sides);

		return result;
	public int oneToSeven (int o) {
		int result = 0;
		if (o == 1) {
			result = d(six) - 3;
			if (result < 1) {
				result = 1;
		if (o == 2) {
			result = d(six) - 2;
			if (result < 1) {
				result = 1;
		if (o == 3) {
result = d(six) - 1;
			if (result < 1) {
				result = 1;
		if (o == 4) {
			result = d(six);
		if (o == 5) {
			result = d(eight);
		if (o == 6) {
			result = d(ten);
		if (o == 7) {
			result = d(twelve);
		return result;
	public int prefix (int p) {
		int prefixTotal = 0;

		for (int i=1; i= 8) {
			int d12s = prefix(full);
			int rest = suffix(mod);
			result = d12s + rest;
			if (result == full+1) {
				fail = true;
		return result;
	public int rollTheDice(boolean addKarma, int stepValue, boolean epicFail) {
		boolean addK = addKarma;
		dice = 0;
		int result = 0;
		result = step(stepValue);
		epicFail = fail;
		if (addK == true) {
			int dK = d(six);
			result = result + dK;
			if (epicFail == true && dK == 1) {
				JOptionPane.showMessageDialog(frame, "Epic FAIL.");
		else if (addK != true && epicFail == true) {
			JOptionPane.showMessageDialog(frame, "Epic FAIL.");

The new resume lesson

Here’s something I didn’t think I’d be saying today:

My resume isn’t perfect.

There are three companies I’ve been dealing with over the last five weeks who were all based in multiple countries. I never thought to add my multiple language proficiencies to my resume; I have a hard time keeping my resume under four pages as it is, and that’s with leaving off references and most of my educational qualifications.

However, I’m near-fluent in French, quite good in German, and have a serious background in Mandarin, Spanish, Greek, and a smattering of a half-dozen other languages. I was coaching a female developer three weeks ago who was applying to a company with multiple locations worldwide–including Latin America, and never thought to tell her that her proficiency in Spanish should certainly come up during her interview.

As companies start to expand and acquire, you may find that your four years of German (no matter how
rusty) can pay off. If you’re proficient in an Asian language, make sure it shows up on your resume in the skills section. If you speak Klingon, email me. I need a translation of Jabberwocky for an ongoing joke I have with my father.

Oh, wait.