Skip to content

Instantly share code, notes, and snippets.

@Vestride Vestride/speedruns.js
Last active Dec 9, 2019

Embed
What would you like to do?
Parses the Halo Waypoint MCC campaign page and calculates your total time as well as a per-mission breakdown of your timings.
(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);
});
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.