/* ** Stupid Copyright Crap: ** ** (c) 2004 by the player of Gravely Mistaken on the Firiona Vie server. ** This is my source code, and I reserve all rights to it. If I have ** provided you with a copy of this source code, I've done so either to ** allow you to see it to learn something, or to allow you to see it to ** teach me something, or so you can compile it to run it. Don't change ** a couple lines and compile it and sell the result as your own work, ** because that's dishonest and it's profiting without my permission off ** of the fruits of my labor, and I didn't write this to make somebody ** else money. Thanks. */ package com.mattihito.eq.combat; import java.io.FileReader; import java.io.BufferedReader; import java.sql.Timestamp; import java.text.DateFormat; import java.util.Date; import com.mattihito.eq.combat.EQCombatInfo; public class ParseEQCombat { public static String EQ_LOG_PATH = "C:\\Program Files\\EverQuest\\Logs"; public static boolean DEBUG = false; public static String PROGRAM = ParseEQCombat.class.getName().substring(ParseEQCombat.class.getName().lastIndexOf(".")+1); public static String VERSION = "1.2.4"; public static String COPYRIGHT = "2004"; public static String AUTHOR = "the player of Gravely Mistaken (Firiona Vie)"; public static String PERMISSION = "free, noncommercial use of this version"; public static String [] VERBS = {"pierce", "slash", "backstab", "crush", "smash", "kick", "bash", "hit"}; public static final String ERROR_001_DESCRIPTION = "FILE NOT FOUND ERROR"; public static final int ERROR_001_EXIT_CODE = 0; public static int W_DMG = 6; public static int W_DMG_AVG = 9; public static int W_PCT_PAREN = 12; public static int W_PCT_ERR_PAREN = 23; // assuming error term is X.XX% not XX.XX% or XXX.XX%. Should be true for large enough n. public static final String LITERAL_ARGUMENT = "literal"; public static void main( String args[] ) { System.out.println(PROGRAM + ", v" + VERSION + ", (c)" + COPYRIGHT + " by " + AUTHOR + "."); System.out.println("The author grants you permission for " + PERMISSION + "."); // begin new argument control, with literal if (args.length == 0) { usage(); } else if (args.length == 1) { help( args[0] ); } else if (args.length > 3) { usage(); } else { boolean literal = false; if ((args.length == 3) && (args[2].toLowerCase().equals(LITERAL_ARGUMENT))) { literal = true; } try { doParse( args, literal ); } catch (Exception e) { e.printStackTrace(); } } // end new argument control, with literal /* // begin old argument control, pre-literal if (args.length != 2) { if (args.length == 1) { help( args[0] ); } else { usage(); } } else { try { doParse( args ); } catch (Exception e) { e.printStackTrace(); } } */ // end old argument control, pre-literal } public static void help( String arg ) { if ((arg.toLowerCase().equals("/?")) || (arg.toLowerCase().equals("/help")) || (arg.toLowerCase().equals("help")) || (arg.toLowerCase().equals("-help")) || (arg.toLowerCase().equals("--help")) || (arg.toLowerCase().equals("h")) || (arg.toLowerCase().equals("-h")) || (arg.toLowerCase().equals("--h")) || (arg.toLowerCase().equals("/h")) || (arg.toLowerCase().equals("?")) || (arg.toLowerCase().equals("-?")) || (arg.toLowerCase().equals("--?")) || (arg.toLowerCase().equals("help")) || (arg.toLowerCase().equals("help"))) { usage(); System.out.println("----"); System.out.println("Known Issues and Bugs:"); System.out.println("1] If a log has timestamps which move backwards in time (due to"); System.out.println("autosynchronizing the computer's clock, or Daylight Saving Time,"); System.out.println("etc.) then ERROR 101, 102, or 103 might display to the user."); System.out.println("There is currently no plan to fix this issue, as there is no real"); System.out.println("consistent way to tell how large the clock synch was."); System.out.println("2] Harm Touches are parsed as procs, because the ability does not"); System.out.println("spawn a \"You begin casting Harm Touch.\" message. While this might"); System.out.println("be fixed in the distant future, I have no immediate plans to do so."); } else { usage(); } } public static void usage() { System.out.println("----"); System.out.println("Usage:"); System.out.println("java " + ParseEQCombat.class.getName() + " -help (OR)"); System.out.println("java " + ParseEQCombat.class.getName() + " [literal]"); System.out.println("This program reads " + EQ_LOG_PATH + "\\eqlog_charname_server.txt"); System.out.println("and searches for melee and spell attacks and damage. For each match of"); System.out.println("an attack, it processes the combat line and summarizes results in the"); System.out.println("standard output. If the literal argument is used, the charname and server"); System.out.println("arguments will be used exactly as passed, otherwise they will be formatted"); System.out.println("such that the charname's first letter is capitalized, and the rest of the"); System.out.println("charname and all of the server are lowercase. The literal argument itself"); System.out.println("is case-insensitive, that is, LiTeRaL works as well as literal and LITERAL."); } public static void doParse( String args[] ) throws Exception { doParse( args ); } public static void doParse( String args[], boolean literal ) throws Exception { String chName = args[0]; String serverName = args[1]; // if !literal, force the character name to be capitalized. if (literal) { System.out.println("Using literal arguments, charname=" + chName + ", server=" + serverName + "."); } else { int chNameLen = chName.length(); if (chNameLen == 1) { chName = chName.toUpperCase(); } else if (chNameLen > 1) { chName = chName.toUpperCase().substring(0, 1) + chName.substring(1, chNameLen).toLowerCase(); } serverName = serverName.toLowerCase(); } System.out.println("-----"); // System.out.println("Character Name: " + chName); // System.out.println("Server Name: " + serverName); Date date = new Date(); Timestamp stamp = new Timestamp(date.getTime()); // System.out.println("Current Date: " + DateFormat.getDateInstance().format( date )); // System.out.println("SQL Timestamp: " + stamp); System.out.println("Character: " + serverName + "." + chName + " Date: " + DateFormat.getDateInstance().format( date ) + " (" + stamp + ")"); String inFileName = new String(EQ_LOG_PATH + "\\eqlog_" + chName + "_" + serverName + ".txt"); FileReader fr = null; BufferedReader br = null; try { fr = new FileReader(inFileName); br = new BufferedReader(fr); } catch (java.io.FileNotFoundException fnfe) { System.out.println(); System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); System.out.println("! ERROR 001: " + ERROR_001_DESCRIPTION + ": Could not find the following log file:"); System.out.println("! "); System.out.println("! " + inFileName); System.out.println("! "); System.out.println("! Please use the -help argument for help."); System.out.println("! Exiting " + PROGRAM + " with code " + ERROR_001_EXIT_CODE); System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); System.exit(ERROR_001_EXIT_CODE); } System.out.println("Log File: " + inFileName); int matches = 0; EQCombatInfo info = new EQCombatInfo(); info.open(); try { String line = br.readLine(); String line2 = br.readLine(); while (line != null) { String verb = isMatch(line, VERBS); if (verb != null) { processMatch(line, verb, info, line2); matches++; } else if (isCrit(line, chName)) { processCrit(line, info, chName); } else if (isDD(line, chName)) { processDD(line, info, chName); } else if (isDS(line)) { processDS(line, info); } else if (isDOT(line)) { processDOT(line, info); } else if (isSpell(line)) { processSpell(line, info); } else if (isCritDD(line)) { processCritDD(line, info); } else if (isSpellFailure(line)) { processSpellFailure(line, info); } else if (isSpellChannel(line)) { processSpellChannel(line, info); } else if (isSpellFizzle(line)) { processSpellFizzle(line, info); } else if (isSRT(line)) { processSRT(line, info); } else if (isZoned(line)) { processZoned(line, info); } line = line2; line2 = br.readLine(); } processEOF(info); } finally { if (DEBUG) System.out.print("Closing streams..."); br.close(); info.close(); if (DEBUG) System.out.println(" done."); } sendOutput(info); } public static String isMatch(String line, String[] verbs) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); for (int i = 0; i < verbs.length; i++) { String test1 = new String("You " + verbs[i] + " "); String test2 = new String("You try to " + verbs[i] + " "); if ((body.startsWith(test1)) || (body.startsWith(test2))) return verbs[i]; } } catch (Exception e) { } return null; } public static boolean isCrit(String line, String charname) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String(charname + " scores a critical hit! ("); String test2 = new String(charname + " lands a Crippling Blow!("); if ((body.startsWith(test1)) || (body.startsWith(test2))) return true; } catch (Exception e) { } return false; } public static boolean isDD(String line, String charname) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String(charname + " hit "); String test2 = new String(" points of non-melee damage."); if ((body.startsWith(test1)) && (body.endsWith(test2))) return true; } catch (Exception e) { } return false; } public static boolean isDS(String line) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("was hit by non-melee for"); String test2 = new String("points of damage."); // not safe to use 0 here because even though a null name would have a space before "was", // we used trim(), so a null-name match would have an index of 0, and we should include it, // as some NPCs in EverQuest have null names. if ((body.indexOf(test1) > -1) && (body.endsWith(test2))) { return true; } } catch (Exception e) { } return false; } public static boolean isSpell(String line) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("You begin casting "); if (body.startsWith(test1)) { return true; } } catch (Exception e) { } return false; } public static boolean isCritDD(String line) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("You deliver a critical blast! ("); String test2 = new String(")"); if ((body.startsWith(test1)) && (body.endsWith(test2))) { return true; } } catch (Exception e) { } return false; } public static boolean isSpellFailure(String line) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("Your spell is interrupted."); if (body.startsWith(test1)) { return true; } } catch (Exception e) { } return false; } public static boolean isSpellChannel(String line) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("You regain your concentration and continue your casting."); if (body.startsWith(test1)) { return true; } } catch (Exception e) { } return false; } public static boolean isSpellFizzle(String line) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("Your spell fizzles!"); if (body.startsWith(test1)) { return true; } } catch (Exception e) { } return false; } public static boolean isSRT(String line) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("Spell recovery time not yet met"); if (body.startsWith(test1)) { return true; } } catch (Exception e) { } return false; } public static boolean isZoned(String line) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("LOADING, PLEASE WAIT..."); if (body.startsWith(test1)) { return true; } } catch (Exception e) { } return false; } public static boolean isDOT( String line ) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("has taken"); String test2 = new String("damage from your"); // not safe to use 0 here because even though a null name would have a space before "was", // we used trim(), so a null-name match would have an index of 0, and we should include it, // as some NPCs in EverQuest have null names. Also, test2 must come after test1. if ((body.indexOf(test1) > -1) && (body.indexOf(test2) > body.indexOf(test1))) { return true; } } catch (Exception e) { } return false; } public static void processDOT( String line, EQCombatInfo info) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("has taken"); String test2 = new String("damage from your"); // not safe to use 0 here because even though a null name would have a space before "was", // we used trim(), so a null-name match would have an index of 0, and we should include it, // as some NPCs in EverQuest have null names. Also, test2 must come after test1. String remainder = ""; int damage = 0; if ((body.indexOf(test1) > -1) && (body.indexOf(test2) > body.indexOf(test1))) { remainder = body.substring(body.indexOf(test1), body.indexOf(test2)).trim(); remainder = remainder.substring(test1.length()).trim(); damage = Integer.parseInt(remainder); info.processDOT( ts, damage ); } } catch (Exception e) { e.printStackTrace(); } } public static void processSpell( String line, EQCombatInfo info) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("You begin casting "); String remainder = ""; if (body.startsWith(test1)) { remainder = body.substring(test1.length()).trim(); info.processSpell( ts, remainder ); } } catch (Exception e) { e.printStackTrace(); } } public static void processCritDD( String line, EQCombatInfo info ) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("You deliver a critical blast! ("); String test2 = new String(")"); String remainder = ""; int damage = 0; if ((body.startsWith(test1)) && (body.endsWith(test2))) { remainder = body.substring(test1.length(), body.lastIndexOf(test2)).trim(); damage = Integer.parseInt(remainder); info.processCritDD( ts, damage ); } } catch (Exception e) { e.printStackTrace(); } } public static void processSpellFailure(String line, EQCombatInfo info) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("Your spell is interrupted."); if (body.startsWith(test1)) { info.processSpellFailure( ts ); } } catch (Exception e) { e.printStackTrace(); } } public static void processSpellChannel(String line, EQCombatInfo info) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("You regain your concentration and continue your casting."); if (body.startsWith(test1)) { info.processSpellChannel( ts ); } } catch (Exception e) { e.printStackTrace(); } } public static void processSpellFizzle(String line, EQCombatInfo info) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("Your spell fizzles!"); if (body.startsWith(test1)) { info.processSpellFizzle( ts ); } } catch (Exception e) { e.printStackTrace(); } } public static void processSRT(String line, EQCombatInfo info) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("Spell recovery time not yet met"); if (body.startsWith(test1)) { info.processSRT( ts ); } } catch (Exception e) { e.printStackTrace(); } } public static void processZoned(String line, EQCombatInfo info) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("LOADING, PLEASE WAIT..."); if (body.startsWith(test1)) { info.processZoned( ts ); } } catch (Exception e) { e.printStackTrace(); } } public static void processEOF(EQCombatInfo info) { info.processEOF(); } public static void processDS( String line, EQCombatInfo info ) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("was hit by non-melee for"); String test2 = new String("points of damage."); int damage = 0; String remainder = ""; if ((body.indexOf(test1) > -1) && (body.endsWith(test2))) { remainder = body.substring(body.indexOf(test1), body.lastIndexOf(test2)).trim(); remainder = remainder.substring(test1.length()).trim(); damage = Integer.parseInt(remainder); info.processDS( ts, damage ); } } catch (Exception e) { e.printStackTrace(); } } public static void processDD( String line, EQCombatInfo info, String charname ) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String(charname + " hit "); String test2 = new String(" points of non-melee damage."); int damage = 0; String remainder = ""; if ((body.startsWith(test1)) && (body.endsWith(test2))) { remainder = body.substring(0, body.lastIndexOf(test2)).trim(); remainder = remainder.substring(remainder.lastIndexOf(" ")).trim(); damage = Integer.parseInt(remainder); info.processDD( ts, damage ); } } catch (Exception e) { e.printStackTrace(); } } public static void processCrit( String line, EQCombatInfo info, String charname ) { try { Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String(charname + " scores a critical hit! ("); String test2 = new String(charname + " lands a Crippling Blow!("); int damage = 0; String remainder = ""; if (body.startsWith(test1)) { remainder = body.substring(test1.length()); int paren = remainder.lastIndexOf(")"); if (paren != -1) { remainder = remainder.substring(0, paren); } else { return; } damage = Integer.parseInt(remainder); info.processCrit( ts, damage ); } else if (body.startsWith(test2)) { remainder = body.substring(test2.length()); int paren = remainder.lastIndexOf(")"); if (paren != -1) { remainder = remainder.substring(0, paren); } else { return; } damage = Integer.parseInt(remainder); info.processCrit( ts, damage ); } } catch (Exception e) { e.printStackTrace(); } } public static void processMatch( String line, String verb, EQCombatInfo info, String line2 ) { try { boolean riposted = false; if ((line2 != null) && (line2.trim().endsWith("YOU, but YOU riposte!"))) riposted = true; Timestamp ts = parseEQDate(line); String body = getLineBody(line); String test1 = new String("You " + verb + " "); String test2 = new String("You try to " + verb + " "); String dmg1 = new String(" points of damage."); String dmg2 = new String(" point of damage."); String dmg3 = new String(", but miss!"); String dmg4 = new String(" blocks!"); String dmg5 = new String(" dodges!"); String dmg6 = new String(" parries!"); String dmg7 = new String(" ripostes!"); String dmg8 = new String("'s magical skin absorbs the blow!"); String dmg9 = new String(" is INVULNERABLE!"); String dmg10 = new String(", but do no damage."); String target = ""; int damage = 0; String word = ""; String remainder = ""; if (body.startsWith(test1)) { remainder = body.substring(test1.length()); int d1 = remainder.lastIndexOf(dmg1); int d2 = remainder.lastIndexOf(dmg2); if (d1 > -1) { remainder = remainder.substring(0, d1); } else if (d2 > -1) { remainder = remainder.substring(0, d2); } else { return; } int last_spc = remainder.lastIndexOf(" "); String strDamage = remainder.substring(last_spc + 1); /*DEBUG*/ //System.out.println("DEBUG: strDamage: " + strDamage); damage = Integer.parseInt(strDamage); target = remainder.substring(0, last_spc-4); info.processHit(ts, target, damage, riposted); } else if (body.startsWith(test2)) { remainder = body.substring(test2.length()); int d3 = remainder.lastIndexOf(dmg3); int d4 = remainder.lastIndexOf(dmg4); int d5 = remainder.lastIndexOf(dmg5); int d6 = remainder.lastIndexOf(dmg6); int d7 = remainder.lastIndexOf(dmg7); int d8 = remainder.lastIndexOf(dmg8); int d9 = remainder.lastIndexOf(dmg9); int d10 = remainder.lastIndexOf(dmg10); if (d3 > -1) { target = remainder.substring(0, d3); info.processMiss(ts, target, riposted); } else if (d4 > -1) { remainder = remainder.substring(0, d4); target = remainder.substring(0, ((remainder.length()-6)/2)); // "name, but name" is 4+6+4 long. info.processBlock(ts, target, riposted); } else if (d5 > -1) { remainder = remainder.substring(0, d5); target = remainder.substring(0, ((remainder.length()-6)/2)); // "name, but name" is 4+6+4 long. info.processDodge(ts, target, riposted); } else if (d6 > -1) { remainder = remainder.substring(0, d6); target = remainder.substring(0, ((remainder.length()-6)/2)); // "name, but name" is 4+6+4 long. info.processParry(ts, target, riposted); } else if (d7 > -1) { remainder = remainder.substring(0, d7); target = remainder.substring(0, ((remainder.length()-6)/2)); // "name, but name" is 4+6+4 long. info.processRiposte(ts, target, riposted); } else if (d8 > -1) { remainder = remainder.substring(0, d8); target = remainder.substring(0, ((remainder.length()-6)/2)); // "name, but name" is 4+6+4 long. info.processRune(ts, target, riposted); } else if (d9 > -1) { remainder = remainder.substring(0, d9); target = remainder.substring(0, ((remainder.length()-6)/2)); // "name, but name" is 4+6+4 long. info.processInvulnerable(ts, target, riposted); } else if (d10 > -1) { target = remainder.substring(0, d10); // "name" is all that remains, we cut ", but do no damage." info.processImmune(ts, target, riposted); } else { System.out.println("ERROR 99: No data retrieved from line: \"" + line + "\", ignoring it."); return; } } else { return; } } catch (Exception e) { e.printStackTrace(); } } public static Timestamp parseEQDate( String line ) throws Exception { if (!(line.startsWith("["))) throw new Exception("Line does not begin with \"[\"."); String monthNameStr = line.substring(5, 8); String dayStr = line.substring(9,11); String timeStr = line.substring(12, 20); String yearStr = line.substring(21,25); String monthStr = getMonthStr( monthNameStr ); String stamp = new String(yearStr + "-" + monthStr + "-" + dayStr + " " + timeStr + ".00"); return Timestamp.valueOf(stamp); } public static String getLineBody( String line ) { if (line.length() < 27) return new String(""); return new String(line.substring(27).trim()); } public static String getMonthStr( String name ) throws Exception { String[] names = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; String[] nums = { "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12" }; for (int i = 0; i < 12; i++) { if (name.equals(names[i])) return nums[i]; } throw new Exception("The month name " + name + " is unknown."); } public static void sendOutput( EQCombatInfo info ) { System.out.println("-----"); System.out.println("First to Last Attack: " + info.getStartStamp() + " to " + info.getEndStamp()); System.out.println("Time Elapsed First to Last: " + info.getTimeinlogString()); System.out.println("Total Time Spent in Combat: " + info.getTimeincombatString() + " (" + info.getTimeincombatPercentage() + ")"); System.out.println("----"); String attacks = String.valueOf(info.getAttacks()); int attack_width = attacks.length(); String procs = String.valueOf(info.getProcs()); int proc_width = procs.length(); String dss = String.valueOf(info.getDmgshields()); int ds_width = dss.length(); String nukes = String.valueOf(info.getNukes()); int nuke_width = nukes.length(); String dots = String.valueOf(info.getDots()); int dot_width = dots.length(); String critdds = String.valueOf(info.getCritDDs()); int cdd_width = critdds.length(); int width1 = attack_width; if (proc_width > width1) width1 = proc_width; if (ds_width > width1) width1 = ds_width; if (nuke_width > width1) width1 = nuke_width; if (dot_width > width1) width1 = dot_width; if (cdd_width > width1) width1 = cdd_width; System.out.print("Number of Hits (Percentage): " + rightJustify(info.getHits(), width1)); System.out.println(rightJustify(new String("(" + info.getHitPercentage() + ")"), W_PCT_PAREN)); System.out.print("Number of Misses (Percentage): " + rightJustify(info.getMisses(), width1)); System.out.println(rightJustify(new String("(" + info.getMissPercentage() + ")"), W_PCT_PAREN)); System.out.print("Number of Dodges (Percentage): " + rightJustify(info.getDodges(), width1)); System.out.println(rightJustify(new String("(" + info.getDodgePercentage() + ")"), W_PCT_PAREN)); System.out.print("Number of Parries (Percentage): " + rightJustify(info.getParries(), width1)); System.out.println(rightJustify(new String("(" + info.getParryPercentage() + ")"), W_PCT_PAREN)); System.out.print("Number of Ripostes (Percentage): " + rightJustify(info.getRipostes(), width1)); System.out.println(rightJustify(new String("(" + info.getRipostePercentage() + ")"), W_PCT_PAREN)); System.out.print("Number of Blocks (Percentage): " + rightJustify(info.getBlocks(), width1)); System.out.println(rightJustify(new String("(" + info.getBlockPercentage() + ")"), W_PCT_PAREN)); System.out.print("Number of Runes (Percentage): " + rightJustify(info.getRunes(), width1)); System.out.println(rightJustify(new String("(" + info.getRunePercentage() + ")"), W_PCT_PAREN)); System.out.print("Number of Invuln. (Percentage): " + rightJustify(info.getInvulnerables(), width1)); System.out.println(rightJustify(new String("(" + info.getInvulnerablePercentage() + ")"), W_PCT_PAREN)); System.out.print("Number of Immune (Percentage): " + rightJustify(info.getImmunes(), width1)); System.out.println(rightJustify(new String("(" + info.getImmunePercentage() + ")"), W_PCT_PAREN)); System.out.println(whitespace(34) + dashes(width1) + rightJustify(dashes(9), W_PCT_PAREN)); System.out.print("Total Number of Attacks Made: " + rightJustify(attacks, width1)); System.out.println(rightJustify(new String("(100.00%)"), W_PCT_PAREN)); System.out.println("----"); System.out.print("Number of Crit Hits (% of hits): " + rightJustify(info.getCrits(), width1)); System.out.println(rightJustify(new String("(" + info.getCritPercentageWithErr() + ")"), W_PCT_ERR_PAREN)); System.out.print("Number of Non-Melee procs (rate): " + rightJustify(procs, width1)); System.out.println(rightJustify(new String("(" + info.getProcRatePercentageWithErr() + ")"), W_PCT_ERR_PAREN)); System.out.print("Number of Non-Melee nukes (rate): " + rightJustify(nukes, width1)); System.out.println(rightJustify(new String("(" + info.getNukeRatePercentage()+ ")"), W_PCT_PAREN)); System.out.print("Number of Crit Non-melee (rate): " + rightJustify(critdds, width1)); System.out.println(rightJustify(new String("(" + info.getCritDDPercentageWithErr() + ")"), W_PCT_ERR_PAREN)); System.out.print("Number of DOT pulses (rate): " + rightJustify(dots, width1)); System.out.println(rightJustify(new String("(" + info.getDotRatePercentage() + ")"), W_PCT_PAREN)); System.out.print("Number of Dmg Shield hits (rate): " + rightJustify(dss, width1)); System.out.println(rightJustify(new String("(" + info.getDmgshieldRatePercentage() + ")"), W_PCT_PAREN)); System.out.println("Note: Above errors correspond to " + com.mattihito.eq.combat.EQCombatInfo.ERR_CONFIDENCE_LEVEL + " confidence."); System.out.println("----"); // System.out.println("Maximum Hit Damage: " + rightJustify(info.getMaxHitDamage(), W_DMG) + " x " + info.getMaxHitFrequency()); // System.out.println("Minimum Hit Damage: " + rightJustify(info.getMinHitDamage(), W_DMG) + " x " + info.getMinHitFrequency()); // System.out.println("Maximum Crit Damage: " + rightJustify(info.getMaxCritDamage(), W_DMG) + " x " + info.getMaxCritFrequency()); // System.out.println("Minimum Crit Damage: " + rightJustify(info.getMinCritDamage(), W_DMG) + " x " + info.getMinCritFrequency()); // System.out.println("Maximum Crit Blast: " + rightJustify(info.getMaxCritDDDamage(), W_DMG) + " x " + info.getMaxCritDDFrequency()); // System.out.println("Minimum Crit Blast: " + rightJustify(info.getMinCritDDDamage(), W_DMG) + " x " + info.getMinCritDDFrequency()); System.out.println("Damage Type " + rightJustify("Max", W_DMG) + rightJustify("Freq", W_DMG+1) + rightJustify("Min", W_DMG+7) + rightJustify("Freq", W_DMG+1) + rightJustify("Avg", W_DMG+7)); System.out.println("Melee Hit: " + rightJustify(info.getMaxHitDamage(), W_DMG) + rightJustify(new String("x " + info.getMaxHitFrequency()), W_DMG+1) + rightJustify(info.getMinHitDamage(), W_DMG+7) + rightJustify(new String("x " + info.getMinHitFrequency()), W_DMG+1) + rightJustify(EQCombatInfo.format(info.getAverageHit(), 2), W_DMG+7)); System.out.println("Melee Crit: " + rightJustify(info.getMaxCritDamage(), W_DMG) + rightJustify(new String("x " + info.getMaxCritFrequency()), W_DMG+1) + rightJustify(info.getMinCritDamage(), W_DMG+7) + rightJustify(new String("x " + info.getMinCritFrequency()), W_DMG+1) + rightJustify(EQCombatInfo.format(info.getAverageCrit(), 2), W_DMG+7)); System.out.println("Crit Blast: " + rightJustify(info.getMaxCritDDDamage(), W_DMG) + rightJustify(new String("x " + info.getMaxCritDDFrequency()), W_DMG+1) + rightJustify(info.getMinCritDDDamage(), W_DMG+7) + rightJustify(new String("x " + info.getMinCritDDFrequency()), W_DMG+1) + rightJustify(EQCombatInfo.format(info.getAverageCritDD(), 2), W_DMG+7)); System.out.println("DD Procs: " + rightJustify(info.getMaxProcDamage(), W_DMG) + rightJustify(new String("x " + info.getMaxProcFrequency()), W_DMG+1) + rightJustify(info.getMinProcDamage(), W_DMG+7) + rightJustify(new String("x " + info.getMinProcFrequency()), W_DMG+1) + rightJustify(EQCombatInfo.format(info.getAverageProc(), 2), W_DMG+7)); System.out.println("Cast Nuke: " + rightJustify(info.getMaxNukeDamage(), W_DMG) + rightJustify(new String("x " + info.getMaxNukeFrequency()), W_DMG+1) + rightJustify(info.getMinNukeDamage(), W_DMG+7) + rightJustify(new String("x " + info.getMinNukeFrequency()), W_DMG+1) + rightJustify(EQCombatInfo.format(info.getAverageNuke(), 2), W_DMG+7)); System.out.println("DOT Pulse: " + rightJustify(info.getMaxDotDamage(), W_DMG) + rightJustify(new String("x " + info.getMaxDotFrequency()), W_DMG+1) + rightJustify(info.getMinDotDamage(), W_DMG+7) + rightJustify(new String("x " + info.getMinDotFrequency()), W_DMG+1) + rightJustify(EQCombatInfo.format(info.getAverageDot(), 2), W_DMG+7)); System.out.println("Dmg Shield: " + rightJustify(info.getMaxDmgshieldDamage(), W_DMG) + rightJustify(new String("x " + info.getMaxDmgshieldFrequency()), W_DMG+1) + rightJustify(info.getMinDmgshieldDamage(), W_DMG+7) + rightJustify(new String("x " + info.getMinDmgshieldFrequency()), W_DMG+1) + rightJustify(EQCombatInfo.format(info.getAverageDmgshield(), 2), W_DMG+7)); System.out.println("----"); String dmg = String.valueOf(info.getTotalDamage()); int width2 = dmg.length(); System.out.print("Melee Damage Done: " + rightJustify(info.getDamage(), width2)); System.out.print(rightJustify(new String("(" + info.getMeleeDmgPercentage() + ")"), W_PCT_PAREN)); System.out.println(rightJustify(info.getParsedMeleeDPSString(), W_PCT_PAREN) + " dps"); System.out.print("Proc Damage Done: " + rightJustify(info.getProcdamage(), width2)); System.out.print(rightJustify(new String("(" + info.getProcDmgPercentage() + ")"), W_PCT_PAREN)); System.out.println(rightJustify(info.getParsedProcDPSString(), W_PCT_PAREN) + " dps"); System.out.print("Nuke Damage Done: " + rightJustify(info.getNukedamage(), width2)); System.out.print(rightJustify(new String("(" + info.getNukeDmgPercentage() + ")"), W_PCT_PAREN)); System.out.println(rightJustify(info.getParsedNukeDPSString(), W_PCT_PAREN) + " dps"); System.out.print("DOT Damage Done: " + rightJustify(info.getDotdamage(), width2)); System.out.print(rightJustify(new String("(" + info.getDotDmgPercentage() + ")"), W_PCT_PAREN)); System.out.println(rightJustify(info.getParsedDotDPSString(), W_PCT_PAREN) + " dps"); System.out.print("Dmg Shld Damage Done: " + rightJustify(info.getDmgshielddamage(), width2)); System.out.print(rightJustify(new String("(" + info.getDmgshieldDmgPercentage() + ")"), W_PCT_PAREN)); System.out.println(rightJustify(info.getParsedDmgshieldDPSString(), W_PCT_PAREN) + " dps"); System.out.print("Total Damage Done: " + dmg + rightJustify("(100.00%)", W_PCT_PAREN)); System.out.println(rightJustify(info.getParsedDPSString(), W_PCT_PAREN) + " dps"); // System.out.println("----"); // // System.out.println("Average Melee Damage Per Hit: " + rightJustify(EQCombatInfo.format(info.getAverageHit(), 2), W_DMG_AVG)); // System.out.println("Average Melee Damage Per Attack: " + rightJustify(EQCombatInfo.format(info.getAverageAttack(), 2), W_DMG_AVG)); // System.out.println("Average Proc Damage per Proc: " + rightJustify(EQCombatInfo.format(info.getAverageProc(), 2), W_DMG_AVG)); // System.out.println("Average Proc Damage per Attack: " + rightJustify(EQCombatInfo.format(info.getAverageProcAttack(), 2), W_DMG_AVG)); // System.out.println("Average Total Damage per Attack: " + rightJustify(EQCombatInfo.format(info.getAverageTotalAttack(), 2), W_DMG_AVG)); System.out.println("----"); // System.out.println("Average APS Over Full Logged Time: " + rightJustify(info.getLoggedDurationAPSString(), W_DMG_AVG) + " aps"); // System.out.println("Average DPS Over Full Logged Time: " + rightJustify(info.getLoggedDurationDPSString(), W_DMG_AVG) + " dps"); // System.out.println("Average APS Over Total Combat Time: " + rightJustify(info.getParsedAPSString(), W_DMG_AVG) + " aps"); System.out.println("Average DPS Over Total Combat Time: " + rightJustify(info.getParsedDPSString(), W_DMG_AVG) + " dps"); // System.out.println("-----"); } public static String whitespace(int spaces) { StringBuffer sbuf = new StringBuffer(""); for (int i = 0; i < spaces; i++) { sbuf.append(" "); } return sbuf.toString(); } public static String dashes(int length) { StringBuffer sbuf = new StringBuffer(""); for (int i = 0; i < length; i++) { sbuf.append("-"); } return sbuf.toString(); } public static String rightJustify(Object o, int spaces) { String str = String.valueOf(o); if (str.length() > spaces) { if (spaces < 7) { return new String("(ERROR)"); } else { return rightJustify("(ERROR)", spaces); } } else if (str.length() == spaces) { return str; } return new String(whitespace(spaces - str.length()) + str); } public static String rightJustify(long l, int spaces) { return rightJustify(String.valueOf(l), spaces); } public static String rightJustify(int i, int spaces) { return rightJustify(String.valueOf(i), spaces); } public static String rightJustify(double d, int spaces) { return rightJustify(String.valueOf(d), spaces); } public static String rightJustify(float f, int spaces) { return rightJustify(String.valueOf(f), spaces); } public static String rightJustify(boolean b, int spaces) { return rightJustify(String.valueOf(b), spaces); } public static String rightJustify(char c, int spaces) { return rightJustify(String.valueOf(c), spaces); } public static String rightJustify(char[] data, int spaces) { return rightJustify(String.valueOf(data), spaces); } }