NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Kongregate Level Extension
// @description Push the Kongregate level cap to 100!
// @namespace resterman
// @version 1.5.3
// @author resterman
// @run-at document-end
// @match http://www.kongregate.com/*
// @grant none
// ==/UserScript==
var UserStorage = {
levelPoints: [],
REAL_MAX_LVL: 75,
FAKE_MAX_LVL: 100,
USER_INFO: 'http://www.kongregate.com/api/user_info.json?username='
};
UserStorage.levelPoints[75] = 57885;
UserStorage.levelPoints[76] = 60485;
UserStorage.levelPoints[77] = 63180;
UserStorage.levelPoints[78] = 65970;
UserStorage.levelPoints[79] = 68855;
UserStorage.levelPoints[80] = 71835;
UserStorage.levelPoints[81] = 74920;
UserStorage.levelPoints[82] = 78110;
UserStorage.levelPoints[83] = 81405;
UserStorage.levelPoints[84] = 84805;
UserStorage.levelPoints[85] = 88310;
UserStorage.levelPoints[86] = 91930;
UserStorage.levelPoints[87] = 95665;
UserStorage.levelPoints[88] = 99515;
UserStorage.levelPoints[89] = 103480;
UserStorage.levelPoints[90] = 107560;
UserStorage.levelPoints[91] = 111765;
UserStorage.levelPoints[92] = 116095;
UserStorage.levelPoints[92] = 116095;
UserStorage.levelPoints[93] = 120550;
UserStorage.levelPoints[94] = 125130;
UserStorage.levelPoints[95] = 129835;
UserStorage.levelPoints[96] = 134675;
UserStorage.levelPoints[97] = 139650;
UserStorage.levelPoints[98] = 144760;
UserStorage.levelPoints[99] = 150005;
UserStorage.levelPoints[100] = 155385;
var Actions = {
HEADER: function () {
createCapChanger();
var ks = new KongScript();
ks.waitFor('active_user', null, 50).then(function (active_user) {
var user = new LevelCapUser(active_user.username());
user.points = active_user.points();
user.getLevel().then(function (level) {
if (level < UserStorage.REAL_MAX_LVL) return;
// Update nav_welcome_box levelbug
var levelbug = document.getElementById('mini-profile-level');
updateLevelbug(levelbug, level);
// Update my kong hover profile
updateMyKongProfile(user);
})
.catch(function (err) {
console.log(err);
});
});
},
CHAT: function () {
var ks = new KongScript();
ks.waitFor('ChatRoom').then(function (cr) {
ks.waitFor('MiniProfile');
})
.then(function (mp) {
ks.waitFor('holodeck');
})
.then(function (h) {
injectChatRoomCode();
injectMiniProfileCode();
});
},
PROFILE: function () {
var user = new ProfileUser();
user.getPoints().then(function (points) {
if (points < UserStorage.levelPoints[UserStorage.REAL_MAX_LVL])
return Promise.reject('No need to update.');
return user.getLevel();
})
.then(function (level) {
// Update level number
var htmlLevel = document.getElementById('user_level')
.getElementsByTagName('a')[1]
.getElementsByTagName('span')[0];
htmlLevel.innerHTML = '' + level;
// Update levelbug
var levelbug = document.getElementById('profile_hgroup')
.getElementsByClassName('levelbug')[0];
updateLevelbug(levelbug, level);
updateProfileProgressBar(user.points, user.level);
})
.catch(function (err) {
console.log(err);
});
},
HOVER_BOX: function () {
var ks = new KongScript();
ks.waitFor('UserProfileHoverbox').then(function (u) {
injectUserProfileHoverbox();
});
}
};
var UpdateActions = [
{
pattern: new RegExp('https?://www.kongregate.com', 'i'),
actions: [Actions.HEADER, Actions.HOVER_BOX]
},
{
pattern: new RegExp('https?://www.kongregate.com/accounts/', 'i'),
actions: [Actions.PROFILE]
},
{
pattern: new RegExp('https?://www.kongregate.com/games/', 'i'),
actions: [Actions.CHAT]
}
];
KongScript = function() {};
KongScript.prototype = {
CHECK_TIMEOUT: 10, // seconds before reaching timeout
CHECK_INTERVAL: 100, // milliseconds between class existance check
/**
* Waits for a class to be defined.
*
* @param {String} className The class name to wait for.
* @param {Number} [timeout=CHECK_TIMEOUT] Seconds before timeout
* @param {Number} [interval=CHECK_INTERVAL] Milliseconds between
* each check.
*
* @return a promise that is fulfilled whenever the class is defined
* and is rejected when the timeout is reached.
*/
waitFor: function (className, timeout, interval) {
if (!className)
return Promise.reject('Class name must be specified.');
timeout = (timeout !== undefined ? timeout : this.CHECK_TIMEOUT);
interval = (interval !== undefined ? interval : this.CHECK_INTERVAL);
return new Promise(function (resolve, reject) {
var checkTimes = timeout * 1000 / interval;
var timeInterval = setInterval(function () {
if (window[className]) {
console.log(className + ' loaded.');
resolve(window[className]);
clearInterval(timeInterval);
} else if (checkTimes-- <= 0) {
console.log('Timeout.');
reject(className + ' couldn\'t be loaded.');
clearInterval(timeInterval);
}
}, interval);
});
}
};
ProfileUser = function () {
this.points = null;
this.level = null;
};
ProfileUser.prototype = {
/**
* Return points based on the points in the loaded profile page.
*/
getPoints: function () {
var promise, user = this;
if (user.points === null) {
promise = new Promise(function (resolve, reject) {
var reps = 0;
var interval = setInterval(function () {
var user_points = document.getElementById('user_points');
var navPoints = user_points ?
user_points.getElementsByClassName('user_metric_stat')[0]
.getElementsByTagName('span') [0] :
null;
if (navPoints) {
var points = parseInt(navPoints.textContent);
user.points = points;
resolve(points);
clearInterval(interval);
}
if (reps++ > 10000) {
reject();
clearInterval(interval);
}
}, 100);
});
} else {
promise = Promise.resolve(user.points);
}
return promise;
},
getLevel: function () {
var user = this;
if (user.level === null) {
var promise = user.getPoints()
.then(function (points) {
var level = UserStorage.REAL_MAX_LVL;
while (level <= UserStorage.FAKE_MAX_LVL &&
points >= UserStorage.levelPoints[level])
level++;
return (user.level = level - 1);
});
return promise;
} else {
return Promise.resolve(user.level);
}
}
};
LevelCapUser = function (username) {
this.username = username;
this.points = null;
this.level = null;
};
LevelCapUser.prototype = {
/**
* Return the user points. If points weren't loaded, it will load them
* with an http request.
*
* @return a promise resolved with user points.
*/
getPoints: function () {
var user = this;
if (user.points === null) {
var promise = HttpGetPromise(UserStorage.USER_INFO + user.username)
.then(function (json) {
return JSON.parse(json).user_vars.points;
})
.then(function (points) {
return (user.points = points);
});
return promise;
} else {
return Promise.resolve(user.points);
}
},
/**
* Return the user level. If points weren't loaded, it will load them
* with an http request.
*
* @return a promise resolverd with user level.
*/
getLevel: function () {
var user = this;
if (user.level === null) {
var promise = user.getPoints()
.then(function (points) {
var level = UserStorage.REAL_MAX_LVL;
while (level <= UserStorage.FAKE_MAX_LVL &&
points >= UserStorage.levelPoints[level])
level++;
return (user.level = level - 1);
});
return promise;
} else {
return Promise.resolve(user.level);
}
}
};
ChatUserStorage = function () {
this.users = {};
};
ChatUserStorage.prototype = {
/**
* Return the level of the user.
*
* @return user level.
*/
getLevel: function (username) {
username = username.toLowerCase();
if (this.users[username] === undefined)
this.users[username] = new LevelCapUser(username);
return this.users[username].getLevel();
}
};
var HttpGetPromise = function (url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.send();
xhr.addEventListener('load', function () {
if (this.status == 200) {
resolve(this.responseText);
} else {
reject(this.statusText);
}
});
xhr.addEventListener('error', function () {
reject(this.statusText);
});
});
};
// Update profile progress bar
function updateProfileProgressBar(points, level) {
if (points >= UserStorage.levelPoints[UserStorage.FAKE_MAX_LVL])
return;
var currLevelPoints = UserStorage.levelPoints[level],
nextLevelPoints = UserStorage.levelPoints[level + 1],
pointsLeft = nextLevelPoints - points,
pointsBetween = nextLevelPoints - currLevelPoints,
percentageRemaining = 100 * (1 - (pointsLeft / pointsBetween));
var pointsInfo = document.createElement('span');
pointsInfo.className = 'points_bar_container';
var pointsInfoP = document.createElement('p');
pointsInfo.appendChild(pointsInfoP);
var pointsBarContainer = document.createElement('points_bar_container');
pointsBarContainer.className = 'points_info mlm';
pointsBarContainer.innerHTML = 'Points needed for next level: <strong class="points_to_level_up">' + pointsLeft + '</strong></span>';
pointsInfoP.appendChild(pointsBarContainer);
var pointsBar = document.createElement('span');
pointsBar.className = 'points_bar mhm';
pointsInfoP.appendChild(pointsBar);
var pointsProgress = document.createElement('span');
pointsProgress.className = 'points_progress';
pointsProgress.setAttribute('style', 'width:' + percentageRemaining + '%;');
pointsBar.appendChild(pointsProgress);
var pointsLevel = createLevelbug(level + 1);
pointsInfoP.appendChild(pointsLevel);
document.getElementById('profile_heading').appendChild(pointsInfo);
}
// Update my kong hover profile
function updateMyKongProfile(user) {
var points = user.points, level = user.level;
// Update levelbug
var userP = document.getElementById('main_nav_mykong')
.getElementsByClassName('user')[0];
updateLevelbug(userP.getElementsByClassName('levelbug')[0], level);
if (level == UserStorage.FAKE_MAX_LVL) return;
// Remove cake and draw points left message, level progress bar and
// next level levelbug
var pointsNeeded = UserStorage.levelPoints[level + 1] - points;
var pointsPercent =
100 * (points - UserStorage.levelPoints[level]) /
(UserStorage.levelPoints[level + 1] - UserStorage.levelPoints[level]);
var pointsP = document.createElement('p');
pointsP.className = 'points';
pointsP.innerHTML = '<strong>'+ pointsNeeded +' points</strong> needed for the next level';
var barP = document.createElement('p');
barP.className = 'progress';
var barSpan = document.createElement('span');
barSpan.className = 'progress_bar';
barP.appendChild(barSpan);
var barPercentSpan = document.createElement('span');
barPercentSpan.className = 'progress_percent';
barPercentSpan.setAttribute('style', 'width:'+ pointsPercent + '%;');
barSpan.appendChild(barPercentSpan);
var levelStrong = document.createElement('strong');
levelStrong.className = 'level';
levelStrong.innerHTML = 'Level';
barP.appendChild(levelStrong);
var levelbug = createLevelbug(level + 1);
levelStrong.appendChild(levelbug);
var cake = document.getElementsByClassName('points w_cake')[0];
var parent = cake.parentNode;
parent.removeChild(cake);
parent.appendChild(pointsP);
parent.appendChild(barP);
}
function injectChatRoomCode () {
ChatRoom.prototype._updateUser = ChatRoom.prototype.updateUser;
ChatRoom.prototype.updateUser = function (a, b) {
holodeck.uStorage = holodeck.uStorage || new ChatUserStorage();
var u = a.variables, chatRoom = this;
if (u.level == UserStorage.REAL_MAX_LVL) {
holodeck.uStorage.getLevel(u.username)
.then(function (level) {
u.level = level;
chatRoom._updateUser(a, b);
});
} else {
this._updateUser(a, b);
}
};
}
function injectMiniProfileCode () {
MiniProfile.prototype.activate = function(a, b) {
this._chat_window.setActiveTempPane(this);
this._current_username = a;
this._current_room = b;
var c = this._container,
d = this._chat_window,
e = this;
$("user_mini_profile").update("");
c.down(".room_name").update(b.name());
d.hideChatWindow();
d._chat_tab_clicked = !1;
c.ieHappyShow();
d.showSpinner();
new Ajax.Updater({
success: "user_mini_profile"
}, "/accounts/" + a + ".chat", {
method: "get",
onComplete: function() {
// Change only if the user is level 65
holodeck.uStorage.getLevel(a).then(function (level) {
var miniProfile = document.getElementById('user_mini_profile');
var levelRegExp = /level_([0-9]*)/i;
if (level >= UserStorage.REAL_MAX_LVL)
miniProfile.innerHTML = miniProfile.innerHTML.replace(levelRegExp, 'level_' + level);
!1 === d._chat_tab_clicked && (d.hideSpinner(), e.setupBanAndSilencingControls(a), active_user.addCapturedSelector("#add_friend"), active_user.addCapturedSelector("#mute_user"));
});
}
});
};
}
function injectUserProfileHoverbox() {
UserProfileHoverbox.prototype._openHoverbox = UserProfileHoverbox.prototype.openHoverbox;
var p = UserProfileHoverbox.prototype.openHoverbox.__proto__;
UserProfileHoverbox.prototype.openHoverbox = function () {
var hoverbox = this;
var user = this._currentUserAnchor.href.match(/accounts\/(.*)/i)[1];
if (this._hoverboxCache[this._currentUserAnchor.href]) {
hoverbox._openHoverbox();
} else {
var u = new LevelCapUser(user);
u.getLevel().then(function (level) {
hoverbox._openHoverbox();
if (level < UserStorage.REAL_MAX_LVL) return;
hoverbox._hoverbox.observe('afterOpen', function(){
var l = hoverbox._hoverbox.container
.getElementsByClassName('mini_profile_level')[0];
l.getElementsByTagName('span')[0].textContent = '' + level;
});
})
.catch(function (err) {
// Open it anyways, but the level may be capped at 65
hoverbox._openHoverbox();
console.log(err);
});
}
};
// Restoring __proto__ because firefox rips if not
UserProfileHoverbox.prototype.openHoverbox.__proto__ = p;
}
function createLevelbug(level) {
var levelbug = document.createElement('span');
levelbug.className = 'spritesite levelbug level_' + level;
levelbug.alt = 'Levelbug ' + level;
levelbug.title = 'Level ' + level;
return levelbug;
}
function updateLevelbug(levelbug, level) {
levelbug.className = levelbug.className.replace(/level_[0-9]*/, 'level_' + level);
levelbug.title = 'Level ' + level;
}
function getFakeMaxLevel() {
var l = localStorage.getItem('fake_max_level');
if (l !== null)
UserStorage.FAKE_MAX_LVL = l;
}
function setFakeMaxLevel() {
var level = window.prompt('Set the new level cap.', UserStorage.FAKE_MAX_LVL);
level = parseInt(level);
if (level > 65 && level <= 100) {
UserStorage.FAKE_MAX_LVL = level;
localStorage.setItem('fake_max_level', level);
} else if (!isNaN(level)) alert('New level cap must be between 66 and 100');
}
// Creates the button to change the level cap
function createCapChanger() {
var levelCapChanger = document.createElement('li');
var levelCapStyle = document.createElement('style');
levelCapStyle.innerHTML = "#level_cap_control::after {border-bottom:1px dotted #9b9a9a;bottom:0;content:'';display:block;left:11px;position:absolute;right:11px;}";
levelCapChanger.appendChild(levelCapStyle);
var linkCapChanger = document.createElement('a');
linkCapChanger.id = 'level_cap_control';
linkCapChanger.innerHTML = 'Level cap';
linkCapChanger.href = '#';
linkCapChanger.addEventListener('click', function () {
setFakeMaxLevel();
});
levelCapChanger.appendChild(linkCapChanger);
var signOut = document.getElementById('welcome_box_sign_out');
var cogList = signOut.parentNode.parentNode;
cogList.insertBefore(levelCapChanger, signOut.parentNode);
}
// Creates new levelbug css classes till level 100
function createLevelbugCSS() {
var levelStyle = document.createElement('style');
for (var i = UserStorage.REAL_MAX_LVL; i <= UserStorage.FAKE_MAX_LVL; i++)
levelStyle.innerHTML += '.level_' + i + '{background-position: 100% ' + ( - 1755 - 20 * (i - UserStorage.REAL_MAX_LVL)) + 'px;}';
document.head.appendChild(levelStyle);
}
function init() {
createLevelbugCSS();
getFakeMaxLevel();
UpdateActions.forEach(function (uAction, i, arr) {
if (uAction.pattern.test(document.URL))
uAction.actions.forEach(function (f, i, arr) { f(); });
});
}
window.addEventListener('load', init);