Last active
December 29, 2020 08:10
-
-
Save glen-cheney/759832a8938baf51903e to your computer and use it in GitHub Desktop.
Parses the Halo Waypoint MCC campaign page and calculates your total time as well as a per-mission breakdown of your timings.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
/** | |
* Par times for each mission. | |
* <mission-id, minutes> | |
*/ | |
var parTimes = { | |
// Halo 1 | |
0: { par: 15, name: 'The Pillar of Autumn' }, | |
1: { par: 20, name: 'Halo' }, | |
2: { par: 20, name: 'The Truth and Reconciliation' }, | |
3: { par: 15, name: 'The Silent Cartographer' }, | |
4: { par: 15, name: 'Assualt on the Control Room' }, | |
5: { par: 15, name: '343 Guilty Spark' }, | |
6: { par: 25, name: 'The Library' }, | |
7: { par: 20, name: 'Two Betrayals' }, | |
8: { par: 15, name: 'Keyes' }, | |
9: { par: 15, name: 'The Maw' }, | |
// Halo 2 | |
30: { par: 0, name: 'The Armory' }, | |
31: { par: 15, name: 'Cairo Station' }, | |
32: { par: 15, name: 'Outskirts' }, | |
33: { par: 15, name: 'Metropolis' }, | |
34: { par: 15, name: 'The Arbiter' }, | |
35: { par: 25, name: 'The Oracle' }, | |
36: { par: 15, name: 'Delta Halo' }, | |
37: { par: 15, name: 'Regret' }, | |
38: { par: 15, name: 'Sacred Icon' }, | |
39: { par: 15, name: 'Quarantine Zone' }, | |
40: { par: 20, name: 'Gravemind' }, | |
41: { par: 15, name: 'Uprising' }, | |
42: { par: 15, name: 'High Charity' }, | |
43: { par: 15, name: 'The Great Journey' }, | |
// Halo 3 | |
70: { par: 15, name: 'Sierra 117' }, | |
71: { par: 20, name: 'Crow\'s Nest' }, | |
72: { par: 20, name: 'Tsavo Highway' }, | |
73: { par: 15, name: 'The Storm' }, | |
74: { par: 15, name: 'Floodgate' }, | |
75: { par: 20, name: 'The Ark' }, | |
76: { par: 20, name: 'The Covenant' }, | |
77: { par: 15, name: 'Cortana' }, | |
78: { par: 20, name: 'Halo' }, | |
// Halo 4 | |
104: { par: 15, name: 'Dawn' }, | |
105: { par: 15, name: 'Requiem' }, | |
106: { par: 20, name: 'Forerunner' }, | |
107: { par: 25, name: 'Infinity' }, | |
108: { par: 20, name: 'Reclaimer' }, | |
109: { par: 20, name: 'Shutdown' }, | |
110: { par: 20, name: 'Composer' }, | |
111: { par: 25, name: 'Midnight' }, | |
// Halo 3: ODST | |
168: { par: 3, name: 'Tayari Plaza' }, | |
169: { par: 4, name: 'Uplift Reserve' }, | |
170: { par: 9, name: 'Kizingo Boulevard' }, | |
171: { par: 13, name: 'ONI Alpha Site' }, | |
172: { par: 10, name: 'NMPD HQ' }, | |
173: { par: 10, name: 'Kikowani Station' }, | |
174: { par: 16, name: 'Data Hive' }, | |
175: { par: 25, name: 'Coastal Highway' }, | |
// Halo: Reach | |
178: { par: 0, name: 'Noble Actual' }, | |
179: { par: 15, name: 'Winter Contingency' }, | |
180: { par: 10, name: 'ONI: Sword Base' }, | |
181: { par: 10, name: 'Nightfall' }, | |
182: { par: 15, name: 'Tip of the Spear' }, | |
183: { par: 25, name: 'Long Night of Solace' }, | |
184: { par: 20, name: 'Exodus' }, | |
185: { par: 20, name: 'New Alexandria' }, | |
186: { par: 20, name: 'The Package' }, | |
187: { par: 20, name: 'The Pillar of Autumn' }, | |
188: { par: 0, name: 'Epilogue' }, | |
189: { par: 0, name: 'Lone Wolf' }, | |
}; | |
function getBestTimes() { | |
var times = $('.best-time').map(function(el) { | |
return $(this).text(); | |
}).get(); | |
return times.map(function(values) { | |
values = values.split(':'); | |
if (values.length === 1) values = [0, 0, 0]; | |
return values.map(function(value) { | |
return parseInt(value, 10); | |
}); | |
}); | |
}; | |
function getTotalSeconds() { | |
var times = getBestTimes(); | |
var seconds = times.reduce(function(memo, time) { | |
return memo + time[2]; | |
}, 0); | |
var minutes = times.reduce(function(memo, time) { | |
return memo + time[1]; | |
}, 0); | |
var hours = times.reduce(function(memo, time) { | |
return memo + time[0]; | |
}, 0); | |
return seconds + minutes * 60 + hours * 60 * 60; | |
}; | |
function getPrettyTime(total, sign) { | |
var prefix = total < 0 ? '-' : sign ? '+' : ''; | |
total = Math.abs(total); | |
var hours = Math.floor(total / 3600); | |
total = total - hours * 3600; | |
var minutes = Math.floor(total / 60); | |
var seconds = total - minutes * 60; | |
if (minutes < 10) { | |
minutes = '0' + minutes; | |
} | |
if (seconds < 10) { | |
seconds = '0' + seconds; | |
} | |
return prefix + hours + ':' + minutes + ':' + seconds; | |
}; | |
function getParTimeDifferences() { | |
var missionIds = $('[data-mission-id]').map(function() { | |
return $(this).attr('data-mission-id'); | |
}); | |
var times = getBestTimes(); | |
var diff = times.map(function(time, i) { | |
var personal = time[0] * 3600 + time[1] * 60 + time[2]; | |
var par = parTimes[missionIds[i]].par * 60; | |
return { | |
personal: personal, | |
difference: personal - par | |
}; | |
}); | |
return diff.map(function(obj, i) { | |
var par = parTimes[missionIds[i]]; | |
return { | |
'Mission': par.name, | |
'Par Time': par.par + ':00', | |
'Your Time': getPrettyTime(obj.personal), | |
'Difference': getPrettyTime(obj.difference, true) | |
}; | |
}); | |
}; | |
var total = getTotalSeconds(); | |
console.log('Total time: ' + getPrettyTime(total)); | |
var differences = getParTimeDifferences(); | |
if (typeof console.table === 'function') { | |
console.table(differences); | |
} else { | |
differences.forEach(function(difference) { | |
console.log(difference); | |
}); | |
} | |
})(); |
Much appreciated!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Any hints on how to use it?