/* RuneTimer.java * This piece of software was written by No_Trim_Slyr aka * Mastermule52 aka Corsika, amongst other various online handles. The author * gives permission to all users of this software in both compiled and source * forms to change, add, and remove code and features from this and any * derivative work of this. Permission to change or remove any COMMENTS * in this source* that are signed by the author of that comment is forbidden. * This includes, but is not limited to, comments referring to the terms and * conditions of using this software* and source*. * Permission to use this software* in an illegal manner of any kind is * strictly forbidden. Permission to use this software* in any way to violate * RuneScape's Terms of Service is strictly forbidden. * * Questions? Comments? Email me - mule52@gmail.com * * tl;dr: don't do stupid shit with my code * * * Note: any use of "software" or "source" apply to this software as well * as any derivative works of this software. * - No_Trim_Slyr, March 18, 2008**//* KNOWN BUGS * Issues with stopping and starting again without restarting. * Solution - store a stop time. On resume, add the difference to the start time * and it should compute as normal. ***/import java.awt.*;import java.applet.*;import java.awt.event.*;import java.util.*;import javax.swing.*;public class RuneTimer extends Applet implements ActionListener, Runnable { /* class variables */ Thread clockThread; Button resetbutton; Button lapbutton; Button startbutton; Button stopbutton; TextArea output; Button enterXPbutton; /* for double buffering, prevents flickering - props to realapplets.com for * having such a good tutorial - trim */ Graphics bufferGraphics; Image offScreen; Dimension dim; /* made these static final class variables to make things easier * turns out I might not have used them all, and their names may not * perfectly reflect their use. - trim */ private static final int buttonWidth = 80; private static final int buttonHeight = 40; private static final int txtWidth = "HH:MM:SS.ddd".length(); private static final int txtHeight = 20; /* Sorry, my shift key sucks on my laptop, so I made these - trim */ private static String colon = ":"; private static String zero = "0"; private static String period = "."; private static String resetTime = "00:00:00.000"; /* The variables that actually mean something. -trim */ private long startTime; private long lapTime; private long stopTime; private int lapCounter; private String timeString; private String totalString; private double xprate; // actually don't NEED this, but too lazy to remove private int xptrip; private String xprateString; /* very important boolean here */ private boolean running; /* public void init - overwrites Applet.init() * Initialize this applet */ public void init() { running = false; // not til the fat lady sings resize(200,285); // this seems to be a good size // sometimes, it doesn't resize automatically though... /* reset important variables */ startTime = 0; stopTime = 0; lapTime = 0; timeString = resetTime; totalString = resetTime; xprate = 0; xptrip = 0; /* set up double buffering */ dim = getSize(); offScreen = createImage(dim.width,dim.height); bufferGraphics = offScreen.getGraphics(); /* initialize buffering */ resetbutton = new Button("Reset"); lapbutton = new Button("Lap"); startbutton = new Button("Start"); stopbutton = new Button("Stop"); enterXPbutton = new Button ("Enter XP"); output = new TextArea(txtWidth, txtHeight); /* layout managers are for pussies */ setLayout(null); resetbutton.setBounds(5,5,48,24); add(resetbutton); startbutton.setBounds(55,5,38,24); add(startbutton); stopbutton.setBounds(95,5,37,24); add(stopbutton); lapbutton.setBounds(134,5,34,24); add(lapbutton); output.setBounds(5,40,175,190); add(output); enterXPbutton.setBounds(5,245,70,24); add(enterXPbutton); /* add listeners */ resetbutton.addActionListener(this); lapbutton.addActionListener(this); startbutton.addActionListener(this); stopbutton.addActionListener(this); enterXPbutton.addActionListener(this); } // end public void init() /* public void destroy() - part of interface Runnable * forgetting this would be a box of aids - trim */ public void destroy() { running = false; clockThread = null; } // end public void destroy /* public void run() - part of interface Runnable * this is what runs... in case run() wasn't enough on the matter */ public void run() { /* only do anything if user has said to run */ while (running) { long time = System.currentTimeMillis(); int lapdiff = (int)(time - lapTime); int startdiff = (int)(time - startTime); /* has the user entered an XP value? */ if (xptrip != 0 && startdiff != 0) { // yes they have xprate = ((xptrip*lapCounter)/(startdiff+0.0))*3600000; if (xprate < 800000.0) { // is it under 800k? try { // what if there is no '.' ? xprateString = (xprate+"").substring(0,(xprate+"").indexOf(".")+3); } catch (StringIndexOutOfBoundsException sioobe) { xprateString = (xprate+""); // no '.' means just use whatever it has } } // end if (xprate < 800000.0) else { // when it's over 800k, bad things happen. // if you are really getting OVER 800k an hour // do you really need to know by how much? xprateString = 800000 + ""; } // end else } // end if (xptrip != 0 && startdiff != 0) // format the ints (lapdiff and startdiff) into strings of time timeString = format(lapdiff); totalString = format(startdiff); repaint(); } } /* public void paint (Graphics) - overwrites Applet.paint(Graphics) * @param g Graphics - the Graphics object that gets painted on this applet */ public void paint(Graphics g) { /* clear the buffer */ bufferGraphics.clearRect(0,0,dim.width,dim.height); bufferGraphics.setColor(Color.white); bufferGraphics.drawRect(55,250,200,200); bufferGraphics.setColor(Color.black); if (running) g.setColor(Color.red); bufferGraphics.drawString(timeString + "", 80,245); bufferGraphics.drawString(totalString + "", 80,257); if (xptrip == 0) // no xp rate given? fail =[ bufferGraphics.drawString("Enter an XP rate",80,269); if (xptrip != 0) // xp rate given? win =] bufferGraphics.drawString(xprateString + "", 80,269); // throw on the buffer g.drawImage(offScreen,0,0,this); } // end public void paint(Graphics) /* public void update(Graphics g) * this is what makes double buffering DOUBLE buffering * and not shitty buffering. */ public void update(Graphics g) { paint(g); } // end public void update(Graphics) /* public void actionPerformed(ActionEvent) - required by interface ActionListener * @param e An ActionEvent (hopefully a button event) that is influencing this Applet */ public void actionPerformed(ActionEvent e) { /* reset button GO! */ if (e.getSource() == resetbutton) { running = false; // And Mother Nature was like sloooowww dowwwnn startTime = 0; lapTime = 0; output.replaceRange("",0,lapCounter*(txtHeight+3)); // clear the TextArea lapCounter = 0; timeString = resetTime; totalString = resetTime; repaint(); return; } // end resetbutton /* start button GO! */ if (e.getSource() == startbutton) { // don't reset lap if the timer wasn't reset! if (startTime == 0) lapTime = System.currentTimeMillis(); // start the engines if we aren't running if (!running) { clockThread = new Thread(this); clockThread.start(); // check if stopped without restarting if (stopTime == 0) startTime = System.currentTimeMillis(); else startTime += (System.currentTimeMillis() - stopTime); // reset the stop time stopTime = 0; } // end if(!running) running = true; repaint(); return; } // end startbutton /* stop button GO! ... that doesn't make sense */ if (e.getSource() == stopbutton) { if (running) { clockThread.stop(); stopTime = System.currentTimeMillis(); } // end if (running) running = false; repaint(); return; } // end stopbutton /* lap button GO! */ if (e.getSource() == lapbutton) { if (!running) return; // epic fail - you can't lap if not running lapCounter++; output.append(timeString + "\n"); lapTime = System.currentTimeMillis(); repaint(); return; } // end lapbutton if (e.getSource() == enterXPbutton) { String userinput = JOptionPane.showInputDialog("Enter the XP/trip value"); try { xptrip = Integer.parseInt(userinput); if (xptrip < 1 || xptrip > 800000) throw new NumberFormatException(); } // end try catch(NumberFormatException nfe) { JOptionPane.showMessageDialog(null,"The number you entered was invalid or did not enter correctly", /*...*/ "An error occured", JOptionPane.ERROR_MESSAGE); } // end catch NumberFormatException } // end enterXPbutton } // end public void actionPerformed(ActionEvent e) /* private String format(int) * turns an int that is a certain number of milliseconds * and turns it into HH:MM:SS.ddd format. - trim * @param diff the difference in milliseconds between two points in time */ private String format(int diff) { int tmpRes = diff%1000; // residual digits diff /= 1000; int tmpSec = diff%60; // seconds diff /= 60; int tmpMin = diff%60; // minutes diff /= 60; int tmpHrs = diff; // hours LOL String tmp = ""; // start with nothing /* remember zero, colon, period are final Strings */ if (tmpHrs < 10) tmp = zero; tmp = tmp + tmpHrs + colon; if (tmpMin < 10) tmp = tmp + zero; tmp = tmp + tmpMin + colon; if (tmpSec < 10) tmp = tmp + zero; tmp = tmp + tmpSec + period; if (tmpRes < 10) tmp = tmp + zero; if (tmpRes < 100) tmp = tmp + zero; tmp = tmp + tmpRes; return tmp; } // end public String format(int)} // end class RuneTimer