crushyourfoes
Version:
A LotRO combat log parser
647 lines (559 loc) • 22.4 kB
JavaScript
(function(exports){
exports.VERSION = "1.0.2";
exports.GetReport = function(player, opponent, log) {
var myDPS = exports.GetTotalDPS(player, opponent, log);
// watch out, these parameters are transposed
var myEvades = exports.ParseEvades(opponent, player, log);
var myBlocks = exports.ParseBlocks(opponent, player, log);
var myParries = exports.ParseParries(opponent, player, log);
var myResists = exports.ParseResists(opponent, player, log);
// then flip back
var myAttacks = exports.NumberOfAttacks(player, opponent, log);
var myPartialAttacks = exports.PartialAttacks(player, log);
var bigHitOut = exports.FindBiggestHit(player, opponent, log);
var myCrits = exports.FindCrits(player, opponent, log);
var myDevCrits = exports.FindDevCrits(player, opponent, log);
var theirDPS = exports.GetTotalDPS(opponent, player, log);
// watch out, these parameters are transposed
var theirEvades = exports.ParseEvades(player, opponent, log);
var theirBlocks = exports.ParseBlocks(player, opponent, log);
var theirParries = exports.ParseParries(player, opponent, log);
var theirResists = exports.ParseResists(player, opponent, log);
// then flip back
var theirAttacks = exports.NumberOfAttacks(opponent, player, log);
var theirPartialAttacks = exports.PartialAttacks(opponent, log);
var bigHitIn = exports.FindBiggestHit(opponent, player, log);
var theirCrits = exports.FindCrits(opponent, player, log);
var theirDevCrits = exports.FindDevCrits(opponent, player, log);
var myTotalAvoidances = myEvades + myBlocks + myParries;
var theirTotalAvoidances = theirEvades + theirBlocks + theirParries;
var mySuccessfulAttacks = myAttacks - theirEvades - theirBlocks - theirParries - theirResists;
var theirSuccessfulAttacks = theirAttacks - myEvades - myBlocks - myParries - myResists;
// avoids div by zero
var myDPA = (myAttacks > 0 && myDPS > 0)
? exports.DamagePerAttack(myAttacks, myDPS)
: 0;
var myDPATaken = (theirAttacks > 0 && theirDPS > 0)
? exports.DamagePerAttack(theirAttacks, theirDPS)
: 0;
var theirAvoidResist = (mySuccessfulAttacks > 0)
? 100 - exports.CalculatePercentage(myAttacks, mySuccessfulAttacks)
: 0;
var myAvoidResist = (theirSuccessfulAttacks > 0)
? 100 - exports.CalculatePercentage(theirAttacks, theirSuccessfulAttacks)
: 0;
var myCritPct = (mySuccessfulAttacks > 0 && myCrits > 0)
? exports.CalculatePercentage(mySuccessfulAttacks, myCrits)
: 0;
var theirCritPct = (theirSuccessfulAttacks > 0 && theirCrits > 0)
? exports.CalculatePercentage(theirSuccessfulAttacks, theirCrits)
: 0;
var myDevCritPct = (mySuccessfulAttacks > 0 && myDevCrits > 0)
? exports.CalculatePercentage(mySuccessfulAttacks, myDevCrits)
: 0;
var theirDevCritPct = (theirSuccessfulAttacks > 0 && theirDevCrits > 0)
? exports.CalculatePercentage(theirSuccessfulAttacks, theirDevCrits)
: 0;
var myBiggestHitOut = bigHitOut[0];
var myBiggestHitIn = bigHitIn[0];
var bigCombatLogOut = bigHitOut[1];
var bigCombatLogIn = bigHitIn[1];
var myKBs = exports.MyKillingBlows(log);
var myKills = exports.WhoDied(log);
var report = "CRUSH YOUR FOES!";
report +="\n===============\n";
report += "\nYour total damage done was " + myDPS;
report += "\nTotal damage done to you was " + theirDPS;
report += "\nYour average damage per attack was " + myDPA;
report += "\nAverage damage you took per attack was " + myDPATaken;
report += "\nThe largest hit you landed was for " + myBiggestHitOut;
report += "\nThe largest hit you took was for " + myBiggestHitIn;
report += "\nYour total number of attempted attacks was " + myAttacks;
report += "\nTotal number of attempted attacks against you was " + theirAttacks;
report += "\nYour number of successful attacks was " + mySuccessfulAttacks;
report += "\nNumber of successful attacks against you was " + theirSuccessfulAttacks;
report += "\nYour combined avoidance/resistance was " + myAvoidResist.toFixed(2) + "%";
report += "\nOpponents' combined avoidance/resistance was " + theirAvoidResist.toFixed(2) + "%";
report += "\nYour critical percentage was " + myCritPct.toFixed(2) + "%";
report += "\nOpponents' critical percentage was " + theirCritPct.toFixed(2) + "%";
report += "\nYour devastating critical percentage was " + myDevCritPct.toFixed(2) + "%";
report += "\nOpponents' devastating critical percentage was " + theirDevCritPct.toFixed(2) + "%";
report += "\n\nDetails of your biggest incoming attack:";
report += "\n\t" + bigCombatLogIn;
report += "\nDetails of your biggest outgoing attack:";
report += "\n\t" + bigCombatLogOut;
if (myKills.length > 0) {
report +="\n\nYou killed the following: ";
mobs = {};
myKills.forEach(function(line) {
if (mobs.hasOwnProperty(line)) {
mobs[line]++;
} else {
mobs[line] = 0;
}
});
for (var who in mobs) {
if (mobs[who] > 1) {
report += "\n\t" + mobs[who] + " x " + who.replace("The","").trim();
} else {
report += "\n\t" + who;
}
}
} else {
report += "\n\nYou killed nothing.";
}
return report;
} // GetReport
/*****************************************************************************
** Parsing functions
*****************************************************************************/
exports.GetNames = function(log) {
var names = [];
log.forEach(function(line) {
var bInter = / interrupted /.exec(line);
var bDefeated = / defeated /.exec(line);
var bSuccumbed = / succumbed /.exec(line);
var bHeader = /^#/.exec(line);
var bLeft = /^Left /.exec(line);
var bJoin = /^Joined /.exec(line);
var bYou = /^You /.exec(line);
var bYour = /^Your /.exec(line);
var bBlow = /^blow /.exec(line);
var bLoot = / contents /.exec(line);
var bLoot2 = / acquired /.exec(line);
var bCure = / cure /.exec(line);
var bChat = /^\[/.exec(line);
// mobs and bosses
var bThe = /^The /.exec(line);
var bBob = /^Bob and Weave /.exec(line);
var bNothing = /^Nothing/.exec(line);
var bIncreased = /^Increased (Morale|Power)/.exec(line);
var bInspiration = /^.* Inspiration/.exec(line);
var bConviction = /^Conviction/.exec(line);
var bLendPower = /^Lend Power/.exec(line);
var bMischievous = /^Mischievous (Glee|Delight)/.exec(line);
var bIgnore;
if (bLeft || bJoin || bDefeated || bInter ||
bHeader || bBlow || bYou || bSuccumbed ||
bLoot || bLoot2 || bYour || bCure || bChat ||
bThe || bBob || bNothing || bIncreased ||
bInspiration || bConviction || bLendPower ||
bMischievous) {
bIgnore = true;
} else {
bIgnore = false;
}
if (! bIgnore) {
var reName = /^(.*) (applied|scored|has)/.exec(line);
if (reName) {
var name = reName[1];
// console.log("[%s] indexof %d length %d", name, names.indexOf(name), names.length);
if (names.indexOf(name) === -1) {
names.push(name);
}
}
}
});
names = names.sort();
return names;
}
//FIXME: bigHit fails on 20140607_1 Llygad The Blade
exports.GetTotalDPS = function(t1, t2, log) {
var totalDPS = 0;
log.forEach(function(line) {
var bDPS = / for /.exec(line);
var bGamble = /\(/.exec(line);
var bTier = /Tier/.exec(line);
if (t2 === "ALL") {
if (bDPS) {
// console.log("bDPS: " + line);
if (line.indexOf(t1) === 0) {
// console.log("t1: " + line);
if (bGamble) {
var rePoints = /for ([\d|,]+) /.exec(line);
var points = parseInt(rePoints[1].replace(",",""));
// console.log("%d - %s", points, line);
totalDPS += points;
} else if (bTier) {
//FIXME: use case Combat_20140510_1.txt
console.log('!!them bTier: ' + line);
} else {
var rePoints = /(\d+)/.exec(line.replace(",",""));
var points = parseInt(rePoints[1]);
totalDPS += points;
// console.log('else point %d - %s', points, line);
} // if bTier
} else {
// console.log("miss: " + line);
} // if indexOf t1
} else {
// console.log("miss: " + line);
} // if bDPS
} else if (t1 === "ALL") {
if (bDPS) {
if (line.indexOf(t2) !== 0) {
// console.log("t2: " + line);
if (bGamble) {
var rePoints = /for ([\d|,]+) /.exec(line);
var points = parseInt(rePoints[1].replace(",",""));
// console.log("%d - %s", points, line);
totalDPS += points;
} else if (bTier) {
var rePoints = /Tier \d+ Damage.* for (\d+)/.exec(line);
// console.log('!!you bTier: ' + line);
if (rePoints) {
// console.dir(damage);
var points = parseInt(rePoints[1].replace(",",""));
totalDPS += points;
}
} else {
var rePoints = /(\d+)/.exec(line.replace(",",""));
var points = parseInt(rePoints[1]);
totalDPS += points;
// console.log('else point %d - %s', points, line);
} // if bTier
} else {
// console.log("miss: " + line);
} // if indexOf t2
} else {
// console.log("miss: " + line);
} // if bDPS
} else { // specific targets
if (bDPS) {
if (line.indexOf(t1) === 0 && line.indexOf(t2) !== -1) {
// console.log("specific target: " + line);
if (bGamble) {
var rePoints = /for ([\d|,]+) /.exec(line);
var points = parseInt(rePoints[1].replace(",",""));
// console.log("%d - %s", points, line);
totalDPS += points;
} else if (bTier) {
console.log('!!spec bTier: ' + line);
} else {
var rePoints = /(\d+)/.exec(line.replace(",",""));
var points = parseInt(rePoints[1]);
totalDPS += points;
// console.log('else point %d - %s', points, line);
} // if bTier
} else {
// console.log("miss: " + line);
} // if indexOf t1 and indexOf t2
} else {
// console.log("miss: " + line);
} // if bDPS
} // if t2 == ALL
});
// console.log('t1: %s t2: %s', t1, t2);
return totalDPS;
}
exports.FindBiggestHit = function(t1, t2, lines) {
//FIXME: Combat_20140606_1.txt biggest incoming attack was shootyman
var hitData = [];
var bigHit = 0;
var bigLog = "";
var strBigHit = "";
lines.forEach(function(line) {
var bDPS = / for /.exec(line);
var bGamble = /\(/.exec(line);
var bTier = /Tier/.exec(line);
if (t2 === "ALL") {
if (bDPS) {
// console.log("bDPS: " + line);
if (line.indexOf(t1) === 0) {
// console.log("t1: " + line);
if (bGamble) {
var rePoints = /for ([\d|,]+) /.exec(line);
var points = parseInt(rePoints[1].replace(",",""));
if (points > bigHit) {
bigHit = points;
strBigHit = points;
bigLog = line;
}
} else if (bTier) {
console.log('!!bh their bTier: ' + line);
} else {
var rePoints = /(\d+)/.exec(line.replace(",",""));
var points = parseInt(rePoints[1]);
if (points > bigHit) {
bigHit = points;
strBigHit = points;
bigLog = line;
}
} // if bTier
} else {
// console.log("miss: " + line);
} // if indexOf t1
} else {
// console.log("miss: " + line);
} // if bDPS
} else if (t1 === "ALL") {
if (bDPS) {
if (line.indexOf(t2) !== 0) {
// console.log("t2: " + line);
if (bGamble) {
var rePoints = /for ([\d|,]+) /.exec(line);
var points = parseInt(rePoints[1].replace(",",""));
if (points > bigHit) {
bigHit = points;
strBigHit = points;
bigLog = line;
}
} else if (bTier) {
var rePoints = /Tier \d+ Damage.* for (\d+)/.exec(line);
var points = parseInt(rePoints[1].replace(",",""));
if (points > bigHit) {
bigHit = points;
strBigHit = points;
bigLog = line;
}
// console.log('!!bh you bTier: ' + line);
} else {
var rePoints = /(\d+)/.exec(line.replace(",",""));
var points = parseInt(rePoints[1]);
if (points > bigHit) {
bigHit = points;
strBigHit = points;
bigLog = line;
}
} // if bTier
} else {
// console.log("miss: " + line);
} // if indexOf t2
} else {
// console.log("miss: " + line);
} // if bDPS
} else { // specific targets
if (bDPS) {
if (line.indexOf(t1) === 0 && line.indexOf(t2) !== -1) {
// console.log("specific target: " + line);
if (bGamble) {
var rePoints = /for ([\d|,]+) /.exec(line);
var points = parseInt(rePoints[1].replace(",",""));
if (points > bigHit) {
bigHit = points;
strBigHit = points;
bigLog = line;
}
} else if (bTier) {
console.log('!!bh spec bTier: ' + line);
} else {
var rePoints = /(\d+)/.exec(line.replace(",",""));
var points = parseInt(rePoints[1]);
if (points > bigHit) {
bigHit = points;
strBigHit = points;
bigLog = line;
}
} // if bTier
} else {
// console.log("miss: " + line);
} // if indexOf t1 and indexOf t2
} else {
// console.log("miss: " + line);
} // if bDPS
} // if t2 == ALL
});
hitData.push(strBigHit);
hitData.push(bigLog);
return hitData;
}
exports.ParseEvades = function(t1, t2, lines) {
var evades = 0;
lines.forEach(function(line) {
var bTried = / tried /.exec(line);
if (t1 === "ALL") {
if (line.indexOf(t2) !== 0
&& line.indexOf(" evaded ") !== -1
&& line.indexOf(" partially " ) === -1) {
evades++;
// console.log("your evades: " + line);
}
} else if (t2 === "ALL") {
if (line.indexOf(t1) === 0
&& line.indexOf(" evaded ") !== -1
&& line.indexOf(" partially " ) === -1) {
evades++;
// console.log("their: " + line);
}
} else {
if (line.indexOf(t1) === 0
&& line.indexOf(" evaded ") !== -1
&& line.indexOf(" partially " ) === -1
&& line.indexOf(t2) !== -1) {
evades++;
}
}
});
return evades;
}
exports.ParseBlocks = function(t1, t2, lines) {
var blocks = 0;
lines.forEach(function(line) {
var bTried = / tried /.exec(line);
if (t1 === "ALL") {
if (line.indexOf(t2) !== 0 && line.indexOf(" blocked ") !== -1 && line.indexOf(" partially " ) === -1) {
blocks++;
// console.log("their: " + line);
}
} else if (t2 === "ALL") {
if (line.indexOf(t1) === 0 && line.indexOf(" blocked ") !== -1 && line.indexOf(" partially " ) === -1) {
blocks++;
// console.log("yours: " + line);
}
} else {
if (line.indexOf(t1) === 0 && line.indexOf(" blocked ") !== -1 && line.indexOf(" partially " ) === -1 && line.indexOf(t2) !== -1) blocks++;
}
});
return blocks;
}
exports.ParseParries = function(t1, t2, lines) {
var parries = 0;
lines.forEach(function(line) {
var bTried = / tried /.exec(line);
if (t1 === "ALL") {
if (line.indexOf(t2) !== 0 && line.indexOf(" parried ") !== -1 && line.indexOf(" partially " ) === -1) {
parries++;
// console.log("their: " + line);
}
} else if (t2 === "ALL") {
if (line.indexOf(t1) === 0 && line.indexOf(" parried ") !== -1 && line.indexOf(" partially " ) === -1) {
parries++;
// console.log("yours: " + line);
}
} else {
if (line.indexOf(t1) === 0 && line.indexOf(" parried ") !== -1 && line.indexOf(" partially " ) === -1 && line.indexOf(t2) !== -1) parries++;
}
});
return parries;
}
exports.DamagePerAttack = function(attacks, totalDamage) {
return Math.round(totalDamage/attacks);
// return (totalDamage/attacks).toFixed(2);
}
exports.NumberOfAttacks = function(t1, t2, lines) {
var attacks = 0;
lines.forEach(function(line) {
if (t1 === "ALL") {
if (line.indexOf(t2) !== 0
&& (line.indexOf(" for ") !== -1
|| line.indexOf(" tried ") !== -1)
&& (line.indexOf(" benefit ") === -1
|| line.indexOf(" heal ") === -1)) { // exclude buffs
attacks++;
// console.log('their attacks: ' + line);
}
} else if (t2 === "ALL") {
if (line.indexOf(t1) === 0 && (line.indexOf(" for ") !== -1 || line.indexOf(" tried ") !== -1)) {
attacks++;
}
// console.log("your attacks: " + line);
} else {
if (line.indexOf(t1) === 0 && line.indexOf(t2) !== -1 && (line.indexOf(" for ") !== -1 || line.indexOf(" tried ") !== -1)) attacks++;
}
});
return attacks;
}
exports.PartialAttacks = function(str, lines) {
var attacks = 0;
// pretty certain is broken... shows everyone's partial hits
lines.forEach(function(line) {
if (line.indexOf(str) !== -1 && line.indexOf(" partially ") !== -1) {
attacks++;
// console.log('partial: ' + line);
}
});
return attacks;
}
exports.ParseResists = function(t1, t2, lines) {
var resists = 0;
lines.forEach(function(line) {
var bTried = / tried /.exec(line); // not used!
if (t1 === "ALL") {
if (line.indexOf(t2) !== 0 && line.indexOf(" resisted ") !== -1) {
resists++;
// console.log('yours: ' + line);
}
} else if (t2 === "ALL") {
if (line.indexOf(t1) === 0 && line.indexOf(" resisted ") !== -1) {
resists++;
// console.log('theirs: ' + line);
}
} else {
if (line.indexOf(t1) === 0 && line.indexOf(" resisted ") !== -1 && line.indexOf(t2) !== -1) {
resists++;
console.log('specific: ' + line);
}
} // t1 == ALL
});
return resists;
}
exports.MyKillingBlows = function(lines) {
var kills = 0;
lines.forEach(function(line) {
if (/Your mighty blow/.exec(line)) {
kills++;
// console.log('killed:' + line);
}
});
return kills;
}
exports.WhoDied = function(lines) {
var names = [];
lines.forEach(function(line) {
var bKilled = /^Your mighty blow defeated (.*)\.$/.exec(line);
if (bKilled) {
names.push(bKilled[1].replace("the","The"));
// console.dir(bKilled);
}
});
return names;
}
exports.FindCrits = function(t1, t2, lines) {
var crits = 0;
lines.forEach(function(line) {
if (t1 === "ALL") {
if (line.indexOf(" applied ") === -1 && (line.indexOf(" critical ") !== -1 || line.indexOf(" devastating ") !== -1) && line.indexOf(t2) !== 0) {
crits++;
// console.log('theirs: t1 %s t2 %s - ', t1,t2,line);
}
} else if (t2 === "ALL") {
if (line.indexOf(" applied ") === -1 && (line.indexOf(" critical ") !== -1 || line.indexOf(" devastating ") !== -1) && line.indexOf(t1) === 0) {
crits++;
// console.log('yours: t1 %s t2 %s - ', t1,t2,line);
}
} else {
if (line.indexOf(" applied ") === -1 && (line.indexOf(" critical ") !== -1 || line.indexOf(" devastating ") !== -1) && line.indexOf(t1) === 0 && line.indexOf(t2) !== -1) {
crits++;
}
}
});
return crits;
}
exports.FindDevCrits = function(t1, t2, lines) {
var crits = 0;
lines.forEach(function(line) {
if (t1 === "ALL") {
if (line.indexOf(" applied ") === -1 && line.indexOf(" devastating ") !== -1 && line.indexOf(t2) !== 0) {
crits++;
// console.log('theirs: t1 %s t2 %s - ', t1,t2,line);
}
} else if (t2 === "ALL") {
if (line.indexOf(" applied ") === -1 && line.indexOf(" devastating ") !== -1 && line.indexOf(t1) === 0) {
crits++;
// console.log('yours: t1 %s t2 %s - ', t1,t2,line);
}
} else {
if (line.indexOf(" applied ") === -1 && line.indexOf(" devastating ") !== -1 && line.indexOf(t1) === 0 && line.indexOf(t2) !== -1) {
crits++;
}
}
});
return crits;
}
exports.CalculatePercentage = function(a, e) {
var factor = 100;
var percentage = e / a * factor.toFixed(2);
return percentage;
}
console.log("CRUSHYOURFOES v%s is loaded", exports.VERSION);
})(typeof exports === "undefined" ? this['CYF'] = {} : exports);