vanilla-wow-addons – Rev 1
?pathlinks?
--[[------------------------------------------------------------------------
DMREPORTER.LUA
This file is designed to be executed by a Lua interpreter. For security
reasons, no executable is included with this package. However, Lua
executables are freely available on the interweb for all platforms that
WoW runs on:
http://lua-users.org/wiki/LuaBinaries
For example, on Windows you need to put Lua.exe into the DamageMeters
directory (or in the path, etc), go to the DamageMeters directory
in a console window, and enter:
lua.exe DMReporter.lua
----
As delivered, this file will create .txt and .csv files with various
reports based upon the data saved in your SavedVariables.lua file.
There is nothing hidden here, so if you desire a particular type of report
not included here and aren't afraid of a little Lua programming, why
not give it a shot?
The Basics:
- You have access to the data: DamageMeters_tables.
- You can call some of the report functions that the mod uses, ie. DamageMeters_DoReport.
- If you choose to use the built-in report functions, not that they will
call the function DamageMeters_SendReportMsg, located in this file.
- You have access to everything in in Localization.lua.
------------------------------------------------------------------------]]--
------------------------------------------------------------------------
-------------
-- OPTIONS --
-------------
-- For convenience the following options below can be toggled to control
-- the output.
if (nil == useSavedTable) then
--useSavedTable = true; -- Whether or not to use the main or memory table.
end
outputFilenameBase = "DMReport"; -- The base filename for all generated files.
--useTimeStamp = true; -- Adds date and time to the filename.
useDateStamp = true; -- Adds date and time to the filename.
useSessionLabel = true; -- Adds the name of the session to the filename.
filenameSuffix = "" -- Added to the end of the filename.
doTotalReport = true; -- Outputs a list of total values for each player.
doLeaderReport = true; -- Outputs lists of the leading players for each value.
doEventReport = true; -- For this to be meaningful, you need to run with event data collection.
createCSVFile = true; -- Outputs the table to a CSV file (for reading by Excel).
createCSVEventFile = true; -- Outputs events to a CSV file.
createClassCSVFile = true; -- Outputs class-by-class summary to a CSV file.
createPercentagesCSVFile = true; -- Outputs percentage summary to a CSV file.
createEventTotalsCSVFile = true; -- Outputs event-totals CSV file.
--createWinrarArchive = true; -- Uses WinRAR (assuming you have it installed) to zip all created reports.
-----------
-- FILES --
-----------
dofile("DMReporter_settings.lua");
dofile("DamageMeters_Globals.lua");
dofile(savedVariablesPath);
dofile("localization.lua");
dofile("DamageMeters_Report.lua");
------------------------------------------------------------------------
-- FUNCTIONS --
------------------------------------------------------------------------
-- Placeholders for built-in WOW functions.
function GetTime() return 0; end
function UnitName(unit) return "["..unit.."]"; end
function DMPrint(msg, color, bSecondChatWindow)
io.write(msg.."\n");
end
------------------------------------------------------------------------
function DamageMeters_SendReportMsg(msg)
-- Send the message to the output file.
outputFileHandle:write(msg.."\n");
end
------------------------------------------------------------------------
-- This is a convenient function for output the main table data to a CSV file.
function DMReporter_OutputToCSV(outputFilename)
-- Open the file.
outputFileHandle = io.open(outputFilename, "w+");
if (nil == outputFileHandle) then
io.write("Error opening "..outputFilename);
return;
end
io.write("(CSV) Reporting to "..outputFilename.."...\n");
-- Generate header string.
local msg, quant;
msg = "Player,Class";
for quant = 1, DMI_REPORT_MAX do
msg = msg..","..DM_QUANTDEFS[quant].name..",Hits,Crits";
end
msg = msg..",,Net Dmg,Net Healing";
DamageMeters_SendReportMsg(msg);
-- Generate per-player strings.
local index;
for index = 1, table.getn(DamageMeters_tables[DMT_ACTIVE]) do
local struct = DamageMeters_tables[DMT_ACTIVE][index];
msg = struct.player..",";
if (struct.class) then
msg = msg..struct.class;
end
local quant;
for quant = 1, DMI_REPORT_MAX do
msg = msg..","..struct.dmiData[quant].q..","..struct.dmiData[quant].hitCount..","..struct.dmiData[quant].critCount;
end
local netDamage = struct.dmiData[DMI_DAMAGE].q - struct.dmiData[DMI_DAMAGED].q;
local netHealing = struct.dmiData[DMI_HEALING].q - struct.dmiData[DMI_HEALED].q;
msg = msg..",,"..netDamage..","..netHealing
DamageMeters_SendReportMsg(msg);
end
-- Close the file.
outputFileHandle:close();
end
function DMReporter_OutputEventsToCSV(outputFilename)
-- Open the file.
outputFileHandle = io.open(outputFilename, "w+");
if (nil == outputFileHandle) then
io.write("Error opening "..outputFilename);
return;
end
io.write("(CSV Events) Reporting to "..outputFilename.."...\n");
-- Generate header string.
local msg, quant;
msg = "Player,Class,Quantity,Event,Total,Hits,Crits,Crit Pct,Avg,Pct of Player,Pct of Group,Dmg Type,Avg Res.";
DamageMeters_SendReportMsg(msg);
groupTotals = {};
local ii;
for ii = 1, table.getn(DamageMeters_tables[DMT_ACTIVE]) do
local q;
for q = 1, DMI_MAX do
if (groupTotals[q] == nil) then
groupTotals[q] = 0;
end
groupTotals[q] = groupTotals[q] + DamageMeters_tables[DMT_ACTIVE][ii].dmiData[q].q;
end
end
-- Generate per-event strings.
local struct, player, playerStruct, quantity, quantityStruct, spell, spellStruct;
for index, struct in DamageMeters_tables[DMT_ACTIVE] do
player = struct.player;
for dmi = 1, DMI_MAX do
quantityStruct = struct.dmiData[dmi].events;
if (quantityStruct) then
local playerClass = "";
local fr = "";
local playerIndex = DamageMeters_GetPlayerIndex(player);
if (playerIndex and playerIndex > 0) then
playerClass = DamageMeters_tables[DMT_ACTIVE][playerIndex].class;
end
if (nil == playerClass) then
playerClass = "";
end
local quantityTotal = 0;
for spell, spellStruct in quantityStruct.spellTable do
if (string.sub(spell, -1) ~= "*") then
quantityTotal = quantityTotal + spellStruct.value;
end
end
for spell, spellStruct in quantityStruct.spellTable do
local average = DM_GetFraction(spellStruct.value, spellStruct.counts[1]);
local pctCrit = 100 * DM_GetFraction(spellStruct.counts[2], spellStruct.counts[1]);
local pctOfPlayer = 100 * DM_GetFraction(spellStruct.value, quantityTotal);
local pctOfGroup = 100 * DM_GetFraction(spellStruct.value, groupTotals[dmi]);
local avgRes = "";
if (spellStruct.resistanceCount > 0) then
avgRes = string.format("%.1f", DM_GetFraction(spellStruct.resistanceSum, spellStruct.resistanceCount));
end
msg = string.format("%s,%s,%s,%s,%d,%d,%.1f,%d,%.1f,%.1f,%.1f,%s,%s",
player,
playerClass,
DMI_NAMES[dmi],
spell,
spellStruct.value,
spellStruct.counts[1],
spellStruct.counts[2],
pctCrit,
average,
pctOfPlayer,
pctOfGroup,
(DM_DMGTYPE_DEFAULT == spellStruct.damageType) and "" or DM_DMGTYPENAMES[spellStruct.damageType],
avgRes);
DamageMeters_SendReportMsg(msg);
end
end
end
end
-- Close the file.
outputFileHandle:close();
end
function DMReporter_OutputEventsTotalsCSV(outputFilename)
-- Open the file.
outputFileHandle = io.open(outputFilename, "w+");
if (nil == outputFileHandle) then
io.write("Error opening "..outputFilename);
return;
end
io.write("(CSV Events) Reporting to "..outputFilename.."...\n");
local spellTable = {};
local quantityTotals = {};
for quantity = 1, DMI_MAX do
spellTable[quantity] = {};
quantityTotals[quantity] = 0;
end
-- Add up all the spells.
local index, player, playerStruct, quantity, quantityStruct, spell, spellStruct;
for index, playerStruct in DamageMeters_tables[DMT_ACTIVE] do
for quantity = 1, DMI_MAX do
eventStruct = playerStruct.dmiData[quantity].events;
if (eventStruct) then
for spell, spellStruct in eventStruct.spellTable do
if (string.sub(spell, -1) ~= "*") then
if (nil == spellTable[quantity][spell]) then
spellTable[quantity][spell] = {};
spellTable[quantity][spell].players = 0;
spellTable[quantity][spell].value = 0;
spellTable[quantity][spell].counts = {};
spellTable[quantity][spell].counts[1] = 0;
spellTable[quantity][spell].counts[2] = 0;
end
spellTable[quantity][spell].players = spellTable[quantity][spell].players + 1;
spellTable[quantity][spell].value = spellTable[quantity][spell].value + spellStruct.value;
spellTable[quantity][spell].counts[1] = spellTable[quantity][spell].counts[1] + spellStruct.counts[1];
spellTable[quantity][spell].counts[2] = spellTable[quantity][spell].counts[2] + spellStruct.counts[2];
quantityTotals[quantity] = quantityTotals[quantity] + spellStruct.value;
end
end
end
end
end
local msg = "Quantity,Spell,Players,Total,Hits,Crits,Average,Pct. Of Total";
DamageMeters_SendReportMsg(msg);
for quantity = 1, DMI_MAX do
local quantityStruct = spellTable[quantity];
for spell, spellStruct in quantityStruct do
local average = DM_GetFraction(spellStruct.value, spellStruct.counts[1]);
local percent = 100 * DM_GetFraction(spellStruct.value, quantityTotals[quantity]);
local msg = string.format("%s,%s,%d,%d,%d,%d,%.1f,%.1f",
DMI_NAMES[quantity],
spell,
spellStruct.players,
spellStruct.value,
spellStruct.counts[1],
spellStruct.counts[2],
average,
percent);
DamageMeters_SendReportMsg(msg);
end
end
-- Close the file.
outputFileHandle:close();
end
function DMReporter_OuptutClassReportCSV(outputFilename)
-- Open the file.
outputFileHandle = io.open(outputFilename, "w+");
if (nil == outputFileHandle) then
io.write("Error opening "..outputFilename);
return;
end
io.write("(CSV Class Report) Reporting to "..outputFilename.."...\n");
--------------------
local classTable = {};
local ix;
local class, classInfo;
for ix = 1, table.getn(DamageMeters_tables[DMT_ACTIVE]) do
local playerInfo = DamageMeters_tables[DMT_ACTIVE][ix];
if (playerInfo.class and playerInfo.class ~= "") then
class = DamageMeters_tables[DMT_ACTIVE][ix].class;
if (classTable[class] == nil) then
classTable[class] = {};
classTable[class].count = 0;
classTable[class].quants = {0, 0, 0, 0};
end
classTable[class].count = classTable[class].count + 1;
local quant;
for quant = 1, DMI_REPORT_MAX do
classTable[class].quants[quant] = classTable[class].quants[quant] + playerInfo.dmiData[quant].q;
end
end
end
-- Generate header string.
local msg, quant;
msg = "Class,Count";
for quant = 1, DMI_REPORT_MAX do
msg = msg..","..DM_QUANTDEFS[quant].name..",Avg "..DM_QUANTDEFS[quant].name;
end
DamageMeters_SendReportMsg(msg);
for class, classInfo in classTable do
local msg = string.format("%s,%d,%d,%d,%d,%d,%d,%d,%d,%d", class, classInfo.count,
classInfo.quants[1], DM_GetFraction(classInfo.quants[1],classInfo.count),
classInfo.quants[2], DM_GetFraction(classInfo.quants[2],classInfo.count),
classInfo.quants[3], DM_GetFraction(classInfo.quants[3],classInfo.count),
classInfo.quants[4], DM_GetFraction(classInfo.quants[4],classInfo.count));
DamageMeters_SendReportMsg(msg);
end
-- Close the file.
outputFileHandle:close();
end
function DMReporter_OutputPercentagesReportCSV(outputFilename)
-- Open the file.
outputFileHandle = io.open(outputFilename, "w+");
if (nil == outputFileHandle) then
io.write("Error opening "..outputFilename);
return;
end
io.write("(CSV Class Report) Reporting to "..outputFilename.."...\n");
--------------------
local msg = "Player,Class"
for ii = 1, DMI_REPORT_MAX do
msg = string.format("%s,%s,Pct Of Total,Pct Of Leader",
msg, DM_QUANTDEFS[ii].name);
end
DamageMeters_SendReportMsg(msg);
-- Calculate totals.
local index;
local info;
local totals = {0, 0, 0, 0, 0, 0};
local peaks = {0, 0, 0, 0};
for index,info in DamageMeters_tables[DMT_ACTIVE] do
local ii;
for ii = 1, DMI_REPORT_MAX do
msg = string.format(",%s,%s,Pct Of Total,Pct Of Leader",
msg, DM_QUANTDEFS[ii].name);
totals[ii] = totals[ii] + info.dmiData[ii].q;
if (info.dmiData[ii].q > peaks[ii]) then
peaks[ii] = info.dmiData[ii].q;
end
end
totals[5] = totals[5] + info.dmiData[DMI_DAMAGE].hitCount;
totals[6] = totals[6] + info.dmiData[DMI_DAMAGE].critCount;
end
DamageMeters_DetermineRanks(DMT_ACTIVE);
for index = 1, table.getn(DamageMeters_tables[DMT_ACTIVE]) do
local struct = DamageMeters_tables[DMT_ACTIVE][index];
local class = struct.class and struct.class or "";
msg = string.format("%s,%s", struct.player, class);
for quant = 1, DMI_REPORT_MAX do
local percentOfTotal = 100 * DM_GetFraction(struct.dmiData[quant].q, totals[quant]);
local percentOfLeader = 100 * DM_GetFraction(struct.dmiData[quant].q, peaks[quant]);
msg = string.format("%s,%d,%.2f,%.2f",
msg, struct.dmiData[quant].q, percentOfTotal, percentOfLeader);
end
DamageMeters_SendReportMsg(msg);
end
-- Close the file.
outputFileHandle:close();
end
------------------------------------------------------------------------
-- REPORT CODE GOES HERE --
------------------------------------------------------------------------
-- See if we are using the "saved" (memory) table, rather than the main table.
if (useSavedTable) then
io.write("Using Saved Table: Switching active index from "..DMT_ACTIVE.." to ");
DMT_ACTIVE = (DMT_ACTIVE == DM_TABLE_B) and DM_TABLE_A or DM_TABLE_B;
io.write(DMT_ACTIVE.."\n");
end
-- Sort functions use the visible table, so make sure it refers
-- to the active table, not the fight table.
DMT_VISIBLE = DMT_ACTIVE;
-- Update DMI_MAX to reflect plugin data.
for plugin, dmi in DamageMeters_pluginDMITable do
if (dmi > DMI_MAX) then
DMI_NAMES[dmi] = plugin;
DMI_MAX = dmi;
end
end
-- Verify that the table has data.
if (nil == DamageMeters_tables[DMT_ACTIVE] or 0 == table.getn(DamageMeters_tables[DMT_ACTIVE])) then
io.write("Table is empty.");
return;
end
local filenameList = {};
local sessionLabel = "";
if (useSessionLabel) then
if (DamageMeters_tableInfo[DMT_VISIBLE].sessionLabel) then
sessionLabel = "_"..DamageMeters_tableInfo[DMT_VISIBLE].sessionLabel;
end
end
-- Build a string which contains the current date and time so that we can
-- uniquely name our report files.
local dateTimeString = "";
if (useDateStamp or useTimeStamp) then
local dateTable = os.date("*t");
if (useDateStamp) then
dateTimeString = string.format("_%d%02d%02d", dateTable.year, dateTable.month, dateTable.day);
end
if (useTimeStamp) then
dateTimeString = dateTimeString..string.format("_%02d%02d%02d", dateTable.hour, dateTable.min, dateTable.sec);
end
end
local fullSuffix = dateTimeString..sessionLabel..filenameSuffix;
if (doTotalReport or doLeaderReport or doEventReport) then
-- Open a file for writing to.
outputFilename = outputFilenameBase..fullSuffix..".txt";
outputFileHandle = io.open(outputFilename, "w+");
if (nil == outputFileHandle) then
io.write("Error opening "..outputFilename);
return;
end
table.insert(filenameList, outputFilename);
io.write("Writing report to "..outputFilename.."...\n");
----------------
-- Total Report:
if (doTotalReport) then
DamageMeters_DoReport(DamageMeters_ReportQuantity_Total, "BUFFER", false, 1, table.getn(DamageMeters_tables[DMT_ACTIVE]), nil);
DamageMeters_SendReportMsg("\n");
end
-- Leader Report:
if (doLeaderReport) then
DamageMeters_DoReport(DamageMeters_ReportQuantity_Leaders, "BUFFER", false, 1, table.getn(DamageMeters_tables[DMT_ACTIVE]), nil);
DamageMeters_SendReportMsg("\n");
end
-- Event Report:
if (doEventReport) then
DamageMeters_DoReport(DamageMeters_ReportQuantity_Events, "BUFFER", false, 1, table.getn(DamageMeters_tables[DMT_ACTIVE]), nil);
DamageMeters_SendReportMsg("\n");
end
-- Close the file.
outputFileHandle:close();
end
-- Dump table to a CSV file.
if (createCSVFile) then
outputFilename = outputFilenameBase..fullSuffix..".csv";
table.insert(filenameList, outputFilename);
DMReporter_OutputToCSV(outputFilename);
end
-- Dump event table to a CSV file.
if (createCSVEventFile) then
outputFilename = outputFilenameBase.."_Events"..fullSuffix..".csv";
table.insert(filenameList, outputFilename);
DMReporter_OutputEventsToCSV(outputFilename);
end
-- Dump Class Info to a CSV file.
if (createClassCSVFile) then
outputFilename = outputFilenameBase.."_Class"..fullSuffix..".csv";
table.insert(filenameList, outputFilename);
DMReporter_OuptutClassReportCSV(outputFilename);
end
-- Dump Percentage Info to a CSV file
if (createPercentagesCSVFile) then
outputFilename = outputFilenameBase.."_Percentages"..fullSuffix..".csv";
table.insert(filenameList, outputFilename);
DMReporter_OutputPercentagesReportCSV(outputFilename);
end
-- Dump event-totals to a CSV file.
if (createEventTotalsCSVFile) then
outputFilename = outputFilenameBase.."_EventTotals"..fullSuffix..".csv";
table.insert(filenameList, outputFilename);
DMReporter_OutputEventsTotalsCSV(outputFilename);
end
---------------------------------
if (createWinrarArchive) then
local archiveName = outputFilenameBase..fullSuffix..".zip";
local commandLine = "start winrar.exe a -df -- "..archiveName;
for index, filename in filenameList do
commandLine = commandLine.." "..filename;
end
io.write("Creating archive using command line:\n");
io.write(commandLine.."\n");
os.execute(commandLine);
end
---------------------------------
if (nil ~= DM_eventCaseTableDebug) then
outputFileHandle = io.open("DM_eventCaseTableDebug.txt", "w+");
outputFileHandle:write("Unparsed Messages in EventCaseTable:\n");
for msgType, msgTable in DM_eventCaseTableDebug do
outputFileHandle:write(" "..msgType.."\n");
for event, eventTable in msgTable do
--DM_DUMP_TABLE(eventTable);
outputFileHandle:write(" "..event.." ("..eventTable.parseCount.."/"..eventTable.hitCount..")\n");
for caseIndex, case in eventTable do
if (type(caseIndex) == "number") then
outputFileHandle:write(" "..case.n.." ("..case.hitCount..")\n");
if (nil ~= case.parsed) then
for parseIx, parse in case.parsed do
outputFileHandle:write(" "..parse.."\n");
end
end
end
end
if (eventTable.unparsed ~= nil) then
outputFileHandle:write(" [Unparsed]:\n");
for index, message in eventTable.unparsed do
outputFileHandle:write(" "..message.."\n");
end
end
end
end
io.close(outputFileHandle);
end
---------------------------------
Generated by GNU Enscript 1.6.5.90.