// ==UserScript==
// @name uftow-stats
// @namespace uftow-stats
// @include https://ubuntuforums.org/showthread.php?t=1579442*
// @version 1.4.0
// @Description Generates stats for Tug of War.
// @grant GM_log
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_listValues
// @grant GM_deleteValue
// @grant GM_registerMenuCommand
// ==/UserScript==
var towConfig = {
multipliers:new Array(
//Forum Moderator
'images/rank_uf_moderator_2013-07.png',-2,
//Forum Super Moderator
'images/rank_uf_super_moderator_2014_12.png',-3,
//Forum Admin
'images/rank_uf_admin_2013-07.png',-4,
//LoCo mods
'font-weight: bold; color: #339900;',2,
//Ubuntu Member
'images/rank_ubuntumember_2013-02.png',2,
//Kubuntu Member - unchanged (2013.02.17)
'images/rebrand/ranks/rankkubuntumember.png',2,
//Staff Emeritus
'images/rank_oldstaff_2013-02.png',3,
//Forum Donators - unchanged (2013.02.13)
'images/rank_forum_donators.png',4,
//Ubuntu Developers - unchanged (2013.02.13)
'images/rank_ubuntudeveloper.png',4,
//Ubuntu One Developers - Unable to verify whether or not this has changed (2013.02.13)
'http://kryogenix.org/random/u1-forums-rank-logo.png',4
)
};
var towStats = {
alreadyHasStartCounting:false,
scores:new Array(),
currentScore:0,
lastPostNumber:0,
lastPoster:null,
winner:null,
init: function(){
this.postContainers=document.getElementsByClassName('postcontainer');
this.firstPostNumber=parseInt(this.postContainers[0].getElementsByClassName('postcounter')[0].textContent.substr(1));
this.lastPostNumber=parseInt(this.postContainers[this.postContainers.length-1].getElementsByClassName('postcounter')[0].textContent.substr(1));
this.currentScore=0;
if(!GM_getValue("statsActive",false)){
this.addStartCounting();
}else{
this.continueCounting();
}
GM_registerMenuCommand("Tug of War: Clear counter",function(){towStats.clearStats();},'A');
},
addStartCounting: function(){
GM_registerMenuCommand("Tug of War: Start counting",function(){towStats.startCounting();},'S');
GM_registerMenuCommand("Tug of War: Continue counting",function(){towStats.continueCounting();},'C');
GM_registerMenuCommand("Tug of War: Show last results",function(){towStats.showSummary();},'R');
this.alreadyHasStartCounting=true;
},
recordPosts: function(startPost){
var postNumber;
var startDiff=startPost-this.firstPostNumber;
var postInfo;
if(startDiff<0 || startPost>this.firstPostNumber+this.postContainers.length-1){
alert("Post #"+startPost+" is not on this page.");
return false;
}
for (var i=startDiff;i<this.postContainers.length;i++){
postInfo=this.getPostInfo(this.postContainers[i]);
this.lastPostNumber=postInfo[3];
if(this.lastPoster==postInfo[0]){
//GM_log("Post #"+this.lastPostNumber+" is a duplicate and has been skipped.");
continue;
}
this.scorePost(postInfo);
if(this.currentScore<=-200){
this.winner='mods';
}else if(this.currentScore>=200){
this.winner='community';
}if(this.winner!=null){
break;
}
//GM_log("Post: "+postInfo[3]+", Round score: "+this.currentScore);
}
return true;
},
getPostInfo: function(postElement){
var userSpanTag=postElement.getElementsByClassName('username')[0].getElementsByTagName('span')[0];
var userName=userSpanTag.textContent;
var css=userSpanTag.getAttribute('style');
var rankURL=postElement.getElementsByClassName('rank')[0].getElementsByTagName('img')[0].getAttribute('src');
var postNumber=parseInt(postElement.getElementsByClassName('postcounter')[0].textContent.substr(1));
return new Array(userName,css,rankURL,postNumber);
},
scorePost: function(postInfo){
this.lastPoster=postInfo[0];
var groupImgIndex=towConfig.multipliers.indexOf(postInfo[2]);
if(groupImgIndex==-1){
groupImgIndex=towConfig.multipliers.indexOf(postInfo[1]);
}
multiplier=(groupImgIndex==-1)?1:towConfig.multipliers[groupImgIndex+1];
this.currentScore+=multiplier;
userIndex=this.scores.indexOf(postInfo[0]);
//The second check in the if statement makes sure users with usernames being actual numbers don't break this script
if(userIndex!=-1&&userIndex%3==0){
this.scores[userIndex+2]++;
}else{
this.scores.push(postInfo[0]);
this.scores.push(multiplier);
this.scores.push(1);
}
},
getSummary: function(){
if(this.winner!=null){
window.alert("Counting complete.\n"+
"The "+((this.currentScore<0)?'-':'')+"200 mark is at post #"+this.lastPostNumber+"\n"+
"Stats will be displayed in the next dialog box.");
}else if(this.scores.length>=3){
window.alert("Tug of War is yet to be completed.\n"+
"Its score is "+this.currentScore+" points as of post #"+this.lastPostNumber+"\n"+
"Intermediate stats will be displayed in the next dialog box.");
}else{
window.alert("Tug of War is yet to be completed.");
return false;
}
var alertText="[B]TUG OF WAR LAST ROUND STATS[/B]\n";
var totalPoints=0;
var totalPosts=0;
var totalModPoints=0;
var totalModPosts=0;
var totalCommunityPoints=0;
var totalCommunityPosts=0;
var totalWinningPoints=0;
var minimumRequiredMVP;
var mvpList=new Array();
var communityParticipants=new Array();
var modParticipants=new Array();
for(var i=1;i<this.scores.length;i+=3){
//GM_log("STATS: User: "+this.scores[i-1]+", Multiplier: "+this.scores[i]+", Points: "+this.scores[i+1]+", Is Mod: "+this.scores[i+2]);
totalPoints+=(this.scores[i+1]*(Math.abs(this.scores[i])));
if(this.scores[i]<0){
totalModPoints+=this.scores[i+1]*(Math.abs(this.scores[i]));
totalModPosts+=this.scores[i+1];
}else if(this.scores[i]>0){
totalCommunityPoints+=this.scores[i+1]*this.scores[i];
totalCommunityPosts+=this.scores[i+1];
}
totalPosts+=this.scores[i+1];
}
totalWinningPoints=(this.currentScore>=0)?totalCommunityPoints:totalModPoints;
minimumRequiredMVP=Math.round(totalWinningPoints*0.15);
alertText+="[B]Total points:[/B] "+totalPoints+" from "+totalPosts+" posts\n";
alertText+="[B]Total community points:[/B] ";
alertText+=((totalCommunityPosts>0)?totalCommunityPoints+" from "+totalCommunityPosts+" posts":"None")+"\n";
alertText+="[B]Total mod points:[/B] ";
alertText+=((totalModPosts>0)?totalModPoints+" from "+totalModPosts+" posts":"None")+"\n";
alertText+="[B]Minimum required for MVP* ("+totalWinningPoints+" x 0.15):[/B] "+minimumRequiredMVP+"\n\n";
for(var i=0;i<this.scores.length;i+=3){
if(this.scores[i+1]<0){
modParticipants.push(this.scores[i]);
modParticipants.push(Math.abs(this.scores[i+1]));
modParticipants.push(this.scores[i+2]);
}else{
communityParticipants.push(this.scores[i]);
communityParticipants.push(this.scores[i+1]);
communityParticipants.push(this.scores[i+2]);
}
}
alertText+="[B]COMMUNITY PARTICIPANTS[/B]\n";
communityStats=this.getListText(communityParticipants,minimumRequiredMVP);
alertText+=communityStats[0]+"\n";
alertText+="[B]MODERATOR PARTICIPANTS[/B]\n";
modStats=this.getListText(modParticipants,minimumRequiredMVP);
alertText+=modStats[0]+"\n";
alertText+="[B]LAST ROUND MVPs[/B]\n";
alertText+="- "+this.lastPoster+" (at post #"+this.lastPostNumber+")\n";
//GM_log("MVP order: "+this.lastPoster+" made the mark at post #"+this.lastPostNumber);
mvpList=(this.currentScore>=0)?communityStats[1]:modStats[1];
for(var i=0;i<mvpList.length;i++){
if(mvpList[i]!=this.lastPoster){
alertText+="- "+mvpList[i]+"\n";
//GM_log("MVP order: "+mvpList[i]+" has spot #"+(i+2));
}
}
alertText+="\n*Starting with second place. The marker gets first place MVP.";
window.alert(alertText);
},
getListText: function(participants,minimumRequiredMVP){
var statsText="";
var thisScore;
var mvpList=new Array();
var reCheck=true;
var tempSpot;
while(reCheck){
reCheck=false;
for(var i=0;i<participants.length;i+=3){
if(i+3>=participants.length){
break;
}
if(participants[i+2]*participants[i+1]<participants[i+5]*participants[i+4]){
tempSpot=new Array(participants[i],participants[i+1],participants[i+2]);
participants[i]=participants[i+3];
participants[i+1]=participants[i+4];
participants[i+2]=participants[i+5];
participants[i+3]=tempSpot[0];
participants[i+4]=tempSpot[1];
participants[i+5]=tempSpot[2];
reCheck=true;
}
}
}
for(var i=0;i<participants.length;i+=3){
thisScore=participants[i+2]*participants[i+1];
statsText+="[B]"+participants[i]+":[/B] "+participants[i+2]+" x "+participants[i+1]+" = "+
thisScore+" point"+((thisScore!=1)?"s":"")+"\n";
//GM_log("Added "+participants[i]+" to the stats list DEBUG: Posts: "+participants[i+2]+", Multiplier: "+participants[i+1]+
// ", Total Score: "+thisScore+", minimumRequiredMVP: "+minimumRequiredMVP);
if(thisScore>=minimumRequiredMVP){
//GM_log("Adding "+participants[i]+" to the MVP list.");
mvpList.push(participants[i]);
}
}
if(participants.length==0){
statsText+="None\n";
}
return new Array(statsText,mvpList);
},
goToNextPage: function(){
var pageLinks=document.getElementsByClassName('pagination_top')[0];
var nextLinkContainer=pageLinks.getElementsByClassName('prev_next')[1];
if(nextLinkContainer!=undefined){
nextLinkContainer.getElementsByTagName('a')[0].click();
return true;
}else{
return false;
}
},
startCounting: function(){
this.clearStats();
theAnswer=window.prompt("Specifiy a post number to begin counting.\n"+
"If you do not know the post number, click Cancel.");
if(theAnswer!=null){
startPost=parseInt(theAnswer);
GM_setValue("statsActive",true);
this.doCounting(startPost);
}
},
continueCounting: function(){
if(this.restoreStats()){
startPost=this.lastPostNumber+1;
GM_setValue("statsActive",true);
this.doCounting(startPost);
}
},
doCounting: function(startPost){
//GM_log("Current round score: "+this.currentScore);
if(!this.recordPosts(startPost)){
this.endCounting();
return false;
}
this.saveStats();
if(this.winner!=null || !this.goToNextPage()){
this.getSummary();
this.endCounting();
}
},
endCounting: function(){
GM_setValue("statsActive",false);
if(!this.alreadyHasStartCounting){
this.addStartCounting();
}
},
showSummary: function(){
if(this.restoreStats()){
this.getSummary();
}
},
saveStats: function(){
//GM_log("Last post on this page: "+this.lastPostNumber);
GM_setValue("lastPostNumber",this.lastPostNumber);
//GM_log("Current round score: "+this.currentScore);
GM_setValue("currentScore",this.currentScore);
for(i=0;i<this.scores.length;i++){
GM_setValue("scores."+i,this.scores[i]);
GM_setValue("scores.count",this.scores.length);
}
GM_setValue("lastPoster",this.lastPoster);
GM_setValue("winner",this.winner);
GM_setValue("statsCached",true);
},
restoreStats: function(){
if(!GM_getValue("statsCached",false)){
window.alert("No cached stats.")
return false;
}
var scoresCount=GM_getValue("scores.count",0);
this.lastPoster=GM_getValue("lastPoster",null);
this.winner=GM_getValue("winner",null);
this.currentScore=parseInt(GM_getValue("currentScore"));
this.lastPostNumber=parseInt(GM_getValue("lastPostNumber"));
this.scores=new Array();
for(i=0;i<scoresCount;i++){
this.scores.push(GM_getValue("scores."+i));
}
return true;
},
clearStats: function(){
this.scores=new Array();
this.currentScore=0;
this.lastPostNumber=0;
this.lastPoster=null;
this.winner=null;
keys=GM_listValues();
for (var i=0,key=null; key=keys[i];i++) {
GM_deleteValue(key);
}
}
};
towStats.init();