Facebook MobWars Helper

By Piotr P. Karwasz Last update Dec 23, 2008 — Installed 90,999 times.

Script mods from TheDruidsKeeper

in
Subscribe to Script mods from TheDruidsKeeper 141 posts, 44 voices



TheDruidsKeeper Scriptwright

Since it was requested, I am going to post all of my mods to the script here. Hopefully with clear enough instructions to be able to use them.
I'll also place each mod as a separate post on this thread so they are easy to find and read.

On page three there are also instructions on how to build an auto-searching script to take advantage of the godfather points awarded with the toolbar (not a part of this script).

Current Modifications (also found in separate posts for manual addition):
- Mean Bank Loss
- Skill Module
- Main Script Fix
- Fighting Items Display
- Header Fix
- Withdraw to Hitlist
- Auto City Buy
- Quick Heal

Small modifications in the full script posted here:
- When there is a captcha it changes the page's title and does not execute the modules
- When there is a script error it sets a timer to refresh the page after 3 seconds
- When there is a Face Book error it will reload the page
- A lot more logging
- Removed the update check since I am too lazy to merge my changes with the new version
- ROI fix from Zen1
- Fixed header error on 3/4/09
- Added a auto-godfather feature to get 2 mobsters when 10 points are available
- Fixed errors caused by site change on 4/9/09
- Fixed errors caused by site change on 4/18/09
- Added Godfather offer preference
- Alternate links that can be used to enable other scripts functionality


// ==UserScript==
// @name Facebook MobWars Helper
// @namespace http://userscripts.org/users/49912
// @description Helps and improves the playing experience of the Facebook application MobWars with automatic functions.
// @source http://userscripts.org/scripts/show/29870
// @identifier http://userscripts.org/scripts/source/29870.user.js
// @version 1.0
// @date 2008-10-05
// @creator Piotr P. Karwasz
// @include http://apps.facebook.com/mobwars/*
// @include http://apps.new.facebook.com/mobwars/*
// ==/UserScript==
/*jsl:option explicit*/
/* $Revision: 184 $ */
//document.body.style.background='black';
var version_timestamp = 1223238452000;
var logLevel = 2;
/***
* logLevel:
* 0 = None
* 1 = Errors, Preformance
* 2 = Beta Test items
* 3 = Everything
*/

/***
* Function: Script Update Checker
*
* Description:
* Script Update Checker (http://userscripts.org/scripts/show/20145)
* written by Jarett (http://userscripts.org/users/38602).
*/
var version_scriptNum = 29870;

/* Errors */
if (document.getElementById('errorTryAgain'))
window.location.href = "http://apps.new.facebook.com/mobwars/";
if (window.location.href == "http://www.facebook.com/common/error.html")
window.setTimeout('window.location.href = "http://apps.new.facebook.com/mobwars/"', 60000);

var Page = new Object();

Page.init = function() {
/* Now */
Page.now = Math.floor(new Date().getTime() / 1000);
var url = location.href;
/* user */
var div;
div = document.getElementById('fb_menu_profile');
div = div.getElementsByTagName('a')[0];
Page.c_user = div.href.match(/id=([0-9]+)/)[1];
var parts = url.split('/');
/* type */
Page.c_page = parts[4];
/* params */
Page.c_params = new Object();
url = parts[5];
if (!url) return;
url = url.split('?');
if (!url[1]) return;
url = url[1];
parts = url.split('&');
for (var i = 0; i < parts.length; i++) {
var param = parts[i].split('=');
Page.c_params[param[0]] = param[1];
}
}

Page.init();
/* vim:set tw=80 sts=2 et ft=javascript: */

var Menu = new Object();

function menu_intToDollars(num) {
num = num || 0;
var str = "";
var tmp;
while (num >= 1000) {
var tmp = num % 1000;
if (tmp > 99) tmp = "" + tmp;
else if (tmp > 9) tmp = "0" + tmp;
else tmp = "00" + tmp;
str = "," + tmp + str;
num = Math.floor(num / 1000);
}
str = "$" + num + str;
return str;
}

Menu.init = function() {
var menuCode = new Array();
menuCode.push('<div class="scriptStatusHeader">-Script status-</div>');
menuCode.push('<table style="width: 100%;"><tr><td>Cash</td><td id="cash_stat"style="color: green; text-align: right;"></td></tr>');
menuCode.push('<tr><td>Bank account</td><td id="bank_stat" style="color: green; text-align: right;"></td></tr>');
menuCode.push('<tr><td>City value</td><td id="city_stat" style="color: green; text-align: right;"></td></tr>');
menuCode.push('<tr><td>Stock value</td><td id="stockpile_stat" style="color: green; text-align: right;"></td></tr>');
menuCode.push('<tr><td colspan="2"><hr/></td></tr>');
menuCode.push('<tr><td>Total</td><td id="total1_stat" style="text-align: right;"></td></tr>');
menuCode.push('<tr><td colspan="2">&nbsp;</td></tr>');
/* Income and expenses */
menuCode.push('<tr><td>City income</td><td id="income_stat" style="color: green; text-align: right;"></td></tr>');
menuCode.push('<tr><td>Mean job payout</td><td id="jobincome_stat" style="color: green; text-align: right;"></td></tr>');
menuCode.push('<tr><td>Mean bank loss</td><td id="bankloss_stat" style="color: red; text-align: right;"></td></tr>');
menuCode.push('<tr><td>Upkeep</td><td id="upkeep_stat" style="color: red; text-align: right;"></td></tr>');
menuCode.push('<tr><td colspan="2"><hr/></td></tr>');
menuCode.push('<tr><td>Total</td><td id="total2_stat" style="color: green; text-align: right;"></td></tr>');
menuCode.push('<tr><td colspan="2">&nbsp;</td></tr>');
/* */
menuCode.push('<tr><td>Attack Strength</td><td id="attackStrength_stat" style="color: green; text-align: right;"></td></tr>');
menuCode.push('<tr><td>Defense Strength</td><td id="defenseStrength_stat" style="color: green; text-align: right;"></td></tr></table>');
menuCode.push('<br/>');

menuCode.push('<div class="scriptStatusContent"><span id="scripterror"></span>Status:<br /><span id="scriptstatus">Resting...</span><br /><span id="scripttimer"></span></div>');
menuCode.push('<div><input type="checkbox" id="quickHeal"' + (GM_getValue("MWHelper_Quickheal", false)? ' checked="checked"' : '') +'>Enable Quickheal</input></div>');
menuCode.push('<div><button type="button" id="prefs_button">Script Preferences</button></div>');

var menu = document.createElement('div');
menu.id = 'ScriptStatus';
menu.innerHTML = menuCode.join('\n');
menuCode.length = 0;

menuCode.push("#ScriptStatus { z-index: 10; position:fixed; bottom:27px; ");
menuCode.push("right:2px; ");
menuCode.push("border:2px solid #6D84B4; background-color:#EEEEEE; color:#3B5998; padding:2px; font-weight:bold; width: 200px; min-height: 100px;}");
menuCode.push("#ScriptStatus div.scriptStatusHeader { text-align:center; background: #6D84B4; color: #FFFFFF; }");
menuCode.push("#ScriptStatus div.scriptStatusContent { border-width: 1px 1px 1px 1px; padding: 2px 2px 2px 2px; border-style: solid solid solid solid;}");

var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = menuCode.join('');

try { document.getElementsByTagName('head')[0].appendChild(style); }
catch(e) {}
document.body.insertBefore(menu, document.body.lastChild);

document.getElementById("quickHeal").addEventListener('click', function (){GM_setValue("MWHelper_Quickheal", this.checked); if (this.checked) quickHeal();}, true);

var button = document.getElementById('prefs_button');
button.addEventListener('click', Preferences.show(), true);
Menu.update();
}

Menu.update = function() {
var el = document.getElementById('cash_stat');
var total = 0;
el.innerHTML = menu_intToDollars(boss.cash);
total += boss.cash || 0;
el = document.getElementById('bank_stat');
el.innerHTML = menu_intToDollars(boss.bank_cash);
total += boss.bank_cash || 0;
el = document.getElementById('city_stat');
el.innerHTML = menu_intToDollars(boss.city_value);
total += boss.city_value || 0;
el = document.getElementById('stockpile_stat');
el.innerHTML = menu_intToDollars(boss.stockpile_value);
total += boss.stockpile_value || 0;
el = document.getElementById('total1_stat');
el.innerHTML = menu_intToDollars(total);
/* Income and upkeep */
el = document.getElementById('income_stat');
el.innerHTML = menu_intToDollars(boss.total_income);
el = document.getElementById('jobincome_stat');
el.innerHTML = menu_intToDollars(boss.job_income);
el = document.getElementById('bankloss_stat');
if (boss.preferences.bank_active)
el.innerHTML = menu_intToDollars(Math.round((boss.total_income + boss.job_income - boss.total_upkeep) * .1));
else
el.innerHTML = menu_intToDollars(0);
el = document.getElementById('upkeep_stat');
el.innerHTML = menu_intToDollars(boss.total_upkeep);
el = document.getElementById('total2_stat');
total = boss.total_income + boss.job_income - boss.total_upkeep;
if (boss.preferences.bank_active)
total = total - Math.round(total * .1);
el.innerHTML = '';
if (total < 0) {
el.style.color = 'red';
el.innerHTML = '-';
}
total = Math.abs(total);
el.innerHTML += menu_intToDollars(total);
var selection = datadisplay_getFightItems();
var attack = datadisplay_getFightPower('attack', selection);
var defense = datadisplay_getFightPower('defense', selection);
el = document.getElementById('attackStrength_stat');
el.innerHTML = attack;
el = document.getElementById('defenseStrength_stat');
el.innerHTML = defense;
}
/* vim:set tw=80 sts=2 et ft=javascript: */

/***
* Object: Utils
*
* Description: contains some utilities functions.
*/
Utils = new Object();

/***
* Method: Element.getElementsByClassName(name, node)
*
* Description:
* Gets a list of elements with a give className.
*
* @param name -- the classname to look for.
* @param node -- node on which we start the search.
* @return array -- an array of nodes matching the classname.
*/
if (document.getElementsByClassName) {
/* Firefox 3: native implementation */
Utils.getElementsByClassName = function(classname, node) {
if (!node) node = document;
return node.getElementsByClassName(classname);
}
} else {
Utils.getElementsByClassName = function(classname, node) {
if (!node) node = document;
var xpathExpression;
var returnElements = new Array();
xpathExpression = ".//*[contains(concat(' ', @class, ' '), ' " + classname + " ')]";
var xpathResult = document.evaluate(xpathExpression, node, null, XPathResult.ANY_TYPE, null);

while (node = xpathResult.iterateNext()) {
returnElements.push(node);
}
return returnElements;
}
}

/***
* Function: Utils.getElementsByXPath(expression, node)
*
* Description:
* Returns an array of elements obtained from evaluating the XPath expression on
* the node.
*
* @param expression -- the expression to evaluate.
* @param node -- context node, defaults to document.
* @return array -- an array of elements matching the expression
*/
Utils.getElementsByXPath = function(expression, node) {
if (!node) node = document;
var result = new Array();
var xpathResult;
xpathResult = document.evaluate(expression, node, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);

var node;
while (node = xpathResult.iterateNext()) {
result.push(node);
}

return result;
}
/* vim:set tw=80 sts=2 et ft=javascript: */

function Boss() {
this.name = 'Anonymous';
this.cash = 0;
this.health = 100;
this.max_health = 100;
this.energy = 10;
this.max_energy = 10;
this.stamina = 3;
this.max_stamina = 3;
this.exp = 0;
this.level = 0;
this.type = 'Unknown';
this.new_level = 0;
this.mobsters = 0;
this.jail_delay = 0;
this.actions = {
"boss_type":{"page":"profile", "url_params":"user_id="
+ Page.c_user, "message":"Checking name and type of your boss", "time":0
}, "boss_attack":{"page":"boss", "message":"Checking attack parameters of your boss", "time":0}};
this.preferences = new Object();
this.hitlist = new Array();
var obj = eval(GM_getValue('boss','({})'));
for (var i in obj) {
this[i] = obj[i];
}
}

Boss.prototype = new Object();

Boss.prototype.save = function() {
GM_setValue('boss', this.toSource());
}

Boss.prototype.updateData = function() {
/* Upgrades */
/* Version 1.0-beta */
//if (!itemlist.item_14 || !itemlist.item_14.stocktype) this.new_level = 1;
/* Jail delay */
boss.jail_delay = 0;
/* Mobsters except myself */
var header = document.getElementById('app8743457343_header');
var str;
if (document.getElementById("app8743457343_navMenu") != null)
str = document.getElementById("app8743457343_navMenu").firstChild.firstChild.childNodes[15].textContent;
if (str.match(/\d+/) != null)
this.mobsters = parseInt(str.match(/\d+/)[0]);
/* Other data */
header = document.getElementById('app8743457343_statusMenu');
var divs = Utils.getElementsByClassName('wrap3outer', header);
for (var i = 0; i < divs.length; i++) {
str = divs[i].innerHTML;
str = str.replace(/,/g,'');

var re = /(Cash|Health|Energy|Stamina|Exp|Level): ?\$?([0-9]+)\/?([0-9]+)?/;
var result = str.match(re);
if (!result) continue;

switch (result[1]) {
case 'Cash':
this.cash = parseInt(result[2]);
break;
case 'Health':
this.health = parseInt(result[2]);
this.max_health = parseInt(result[3]);
break;
case 'Energy':
this.energy = parseInt(result[2]);
this.max_energy = parseInt(result[3]);
break;
case 'Stamina':
this.stamina = parseInt(result[2]);
this.max_stamina = parseInt(result[3]);
break;
case 'Exp':
this.exp = parseInt(result[2]);
break;
case 'Level':
if (this.level != parseInt(result[2])) this.new_level = 1;
this.level = parseInt(result[2]);
break;
default:
alert("Unknown field: " + str);
}
}
this.cash = parseInt(document.getElementById("app8743457343_cur_cash").innerHTML.replace(/,/g, "").replace("$", ""));
this.health = parseInt(document.getElementById("app8743457343_cur_health").innerHTML.replace(/,/g, "").replace("$", ""));
var mystring = document.getElementById("app8743457343_cur_health").parentNode.innerHTML;
var re2 = /\/([0-9]+)/;
var foo = mystring.match(re2);
this.max_health = parseInt(foo[1]);
this.stamina = parseInt(document.getElementById("app8743457343_cur_recovery").innerHTML.replace(/,/g,"").replace("$", ""));
mystring = document.getElementById("app8743457343_cur_recovery").parentNode.innerHTML;
foo = mystring.match(re2);
this.max_stamina = parseInt(foo[1]);
this.energy = parseInt(document.getElementById("app8743457343_cur_energy").innerHTML.replace(/,/g, "").replace("$", ""));
mystring = document.getElementById("app8743457343_cur_energy").parentNode.innerHTML;
foo = mystring.match(re2);
this.max_energy = parseInt(foo[1]);

switch (Page.c_page) {
case 'boss':
header = document.getElementById('app8743457343_content');
divs = header.getElementsByTagName('tr');
this.attack_strength = parseInt(divs[1].getElementsByTagName('td')[1].innerHTML);
this.defense_strength = parseInt(divs[2].getElementsByTagName('td')[1].innerHTML);
break;
case 'jail':
header = document.getElementById('app8743457343_content');
divs = header.getElementsByTagName('p');
for (var i = 0; i < divs.length; i++) {
var delay = divs[i].innerHTML.match(/jail in ([0-9.]+) hour/);
if (delay) {
delay = parseFloat(delay[1]) + 0.01;
this.jail_delay = Page.now + Math.floor(3600 * delay);
break;
}
}
break;
case 'profile':
if (Page.c_page == 'profile' && Page.c_params.user_id == Page.c_user) {
header = document.getElementById('app8743457343_content');
header = header.getElementsByTagName('h1')[0].innerHTML;
var result = header.match(/"(.*)", Level [0-9]+ (\w+)/);
this.name = result[1];
this.type = result[2];
}
break;
}
this.save();
}

GM_registerMenuCommand("Reset MobWars' script database...",
function() {
GM_setValue('boss', '({})');
GM_setValue('inventory', '({})');
GM_setValue('itemlist', '({})');
GM_setValue('jobs', '({})');
});

/* vim:set tw=80 sts=2 et ft=javascript: */

function Stockitem() {
this.type = 'stockpile';
this.name = 'Unknown';
this.attack = 0;
this.defense = 0;
this.upkeep = 0;
this.price = 0;
}

function Cityitem() {
this.type = 'city';
this.name = 'Unknown';
this.price = 0;
this.income = 0;
this.depends = '';
}

function Prepitem() {
this.type = 'prep';
this.name = 'Unknown';
this.energy_per_unit = 0;
}

function Itemlist() {
var obj = eval(GM_getValue('itemlist','({})'));
for (var i in obj) {
this[i] = obj[i];
}
}

Itemlist.prototype = new Object();

Itemlist.prototype.save = function() {
GM_setValue('itemlist', this.toSource());
}

Itemlist.prototype.updateData = function() {
var pages = ['stockpile', 'jobs', 'city'];
if (pages.indexOf(Page.c_page) != -1) {
var pageStocktype;
if (Page.c_page == 'stockpile'){
if (document.location.href.indexOf("show_type=") > -1)
pageStocktype = document.location.href.substring(document.location.href.indexOf("show_type=") + 10)
else if (document.location.href.indexOf("pawn_shop") == -1)
pageStocktype = "weapon";
if (document.location.href.indexOf("power_item") > -1) pageStocktype = "weapon";
}
for (var item in this) {
if (this[item].type != Page.c_page) continue;
if (this[item].stocktype != pageStocktype) continue;
delete this[item];
}
var header = document.getElementById('app8743457343_content');
var divs = Utils.getElementsByXPath('.//a[contains(@name,"item")]',header);
for (var i = 0; i < divs.length; i++) {
var div = divs[i].parentNode.parentNode;
var item_id = divs[i].name;
var item;
switch(Page.c_page) {
case 'stockpile':
item = new Stockitem();
item.stocktype = pageStocktype;
break;
case 'city':
item = new Cityitem();
break;
case 'jobs':
if (Utils.getElementsByXPath('.//a[contains(@href,"item")]/following-sibling::span', div)[0].innerHTML.match(/\%/))
continue;
else
item = new Prepitem();
break;
default:
}
/* The name of the item */
if (Page.c_page != 'jobs') item.name = div.getElementsByTagName('img')[0].title;
else {
var img = Utils.getElementsByXPath('.//a[contains(@href,"item")]/following-sibling::span', div)[0];
item.name = img.previousSibling.title.match(/[0-9]+ (.*)/)[1];
}
/* The items data */
var result;
var str = div.innerHTML.replace(/\n/g,'');
switch (Page.c_page) {
case 'jobs':
div = divs[i].parentNode.parentNode.parentNode.parentNode.parentNode.parentNode;
str = div.innerHTML.replace(/\n/g,'');
result = str.match(/Energy:&nbsp;(\d+).*\(\+(\d+)\)/);
if (result != null)
item.energy_per_unit = result[1] / result[2];
else
item.energy_per_unit = 15;
if (logLevel >= 3) GM_log("Item: " + item.name + " Energy: " + item.energy_per_unit);
break;
case 'city':
result = str.match(/Income: \$([0-9,]+).*\$([0-9,]+).*Owned: <[^<]*>(\d+)/);
item.income = parseInt(result[1].replace(/,/g,''));
/* Base price */
item.price = parseInt(result[2].replace(/,/g,'')) * 10 / (parseInt(result[3]) + 10);
/* Dependencies */
result = str.match(/Built On: (\w+ \w+)/);
if (result) {
for (var j in this) {
if (this[j].name == result[1]) {
item.depends = j;
break;
}
}
}
break;
case 'stockpile':
result = str.match(/Attack: (\d+)/);
if (result) item.attack = parseInt(result[1]);
result = str.match(/Defense: (\d+)/);
if (result) item.defense = parseInt(result[1]);
result = str.match(/upkeep.>\$([0-9,]+)/);
if (result) item.upkeep = parseInt(result[1].replace(/,/g,''));
result = str.match(/\$([0-9,]+)[^\$]*Owned/);
if (result) item.price = parseInt(result[1].replace(/,/g,''));
break;
default:
break;
}
this[item_id] = item;
}
this.save();
}
}

/* vim:set tw=80 sts=2 et ft=javascript: */

Preferences = new Object();

Preferences.init = function() {
/* The handlers for preferences */
this.handlers = new Array();
this.div = document.createElement('div');
this.div.className = 'facebook-gm-pref';
var css = ".facebook-gm-pref {display: none; position: absolute; z-index: 99; left: 200px; top: 200px;"
+ "overflow: visible; background-color: white; border: 1px solid black; padding: 10px; min-width: 400px; min-height: 400px}";
GM_addStyle(css);

/* Setting title */
this.div.innerHTML = '<h2>Script Preferences</h2>';

/* Rule */
this.rule = document.createElement('hr');
this.rule.id = 'facebook-gm-rule';
this.div.appendChild(this.rule);

/* Building form */
this.form = document.createElement('form');
this.form.action = '';
this.form.method = '';
this.form.id = 'facebook-gm-pref';
this.div.appendChild(this.form);

/* Submit button */
this.button = document.createElement('button');
this.button.type = 'button';
this.button.id = 'pref_submit';
this.button.innerHTML = "Update preferences";
this.form.appendChild(this.button);
document.getElementsByTagName('body')[0].appendChild(this.div);
}

Preferences.populate = function(obj) {
/* Preferences display */
for (var i = 0; i < modules.length; i++) {
if (obj[modules[i] + '_preferencesInterface']) obj[modules[i] + '_preferencesInterface'](this);
}
/* Preferences handlers */
for (var i = 0; i < modules.length; i++) {
if (obj[modules[i] + '_preferencesHandler']) this.handlers.push(obj[modules[i] + '_preferencesHandler']);
}
/* Add event listener */
this.button.addEventListener('click', this.eventListener(), true);
this.form.addEventListener('submit', this.eventListener(), true);
}

Preferences.eventListener = function() {
var prefs = this;
return function(ev) {
var reload = false;
var boss = eval(GM_getValue('boss', '({})'));
/* Prevent submitting the form to the server */
ev.preventDefault();
/* Execute all handlers */
for (var i = 0; i < prefs.handlers.length; i++) {
if (prefs.handlers[i](prefs.form, boss)) reload = true;;
}
prefs.div.style.display = 'none';
GM_setValue('boss', boss.toSource());
if (reload) location.reload();
}
}

Preferences.show = function() {
var div = this.div;
return function() {
div.style.display = 'block';
div.scrollIntoView(false);
}
}

Preferences.init();
/* vim:set tw=80 sts=2 et ft=javascript: */

/* Modules */
var modules = ['inventory', 'datadisplay', 'bank', 'hospital', 'jobs', 'skill', 'autoCityBuy', 'autoGodfather'];
//var modules = ['hitlist', 'inventory', 'datadisplay', 'bank', 'hospital', 'jobs'];
//#include "hitlist.module.js"

Timer = new Object();

Timer.start = function(next_page, message, timer) {
var span = document.getElementById('scriptstatus');
span.innerHTML = message;
span = document.getElementById('scripttimer');
/* Convert seconds to string */
var sec = timer;
var str = (sec % 60) + ' s';
sec = Math.floor(sec / 60);
if (sec) {
str = (sec % 60) + ' m ' + str;
sec = Math.floor(sec / 60);
if (sec) str = sec + ' h ' + str;
}
span.innerHTML = 'in ' + str;

if (timer <= 0) {
if (typeof next_page == 'object') {
next_page.click();
setTimeout(Timer.start, 5000, window.location.href, message, timer);
} else {
location.href = next_page;
}
} else {
timer--;
setTimeout(Timer.start, 1000, next_page, message, timer);
}
}
/* vim:set tw=80 sts=2 et ft=javascript: */

/* Global object */
var inventory = eval(GM_getValue('inventory', '({})'));

function inventory_exec() {
boss.city_check = boss.city_check || 0;
boss.stockpile_check = boss.stockpile_check || 0;
var pages = ['jobs', 'city', 'stockpile'];
/* Update the number of items that we have */
if (pages.indexOf(Page.c_page) != -1) {
var header = document.getElementById('app8743457343_content');
var divs = Utils.getElementsByXPath('.//a[contains(@name,"item")]',header);
for (var i = 0; i < divs.length; i++) {
var div = divs[i].parentNode.parentNode;
var isPrepJob = div.innerHTML.match(/dojob/);
if (Page.c_page == 'jobs' && isPrepJob == null) div = divs[i].parentNode.parentNode.parentNode.parentNode.parentNode.parentNode;
var result = div.innerHTML.match(/Owned: (<[^<]*>)?(\d+)/);
if (result) inventory[divs[i].name] = parseInt(result[2]);
if (result && logLevel >= 3) GM_log("You have " + inventory[divs[i].name] + " of " + divs[i].name);
}
GM_setValue('inventory', inventory.toSource());
}
/* If we changed level update lists now */
if (boss.new_level) {
boss.city_check = 1;
boss.stockpile_check = 1;
}
/* Update data */
switch (Page.c_page) {
case 'city':
if (boss.city_check < Page.now) {
itemlist.updateData();
boss.city_check = Page.now + 3600;
}
var total_income = 0;
var city_value = 0;
for (var item in itemlist) {
if (itemlist[item].type != 'city') continue;
var owned = inventory[item] || 0;
total_income += owned * itemlist[item].income;
var price = itemlist[item].price / 2;
while (owned) {
if (owned >= 10) {
city_value += (10 + owned) * price;
owned -= 10;
} else {
city_value += (10 + owned) * owned * price / 10;
owned = 0;
}
}
}
boss.total_income = total_income;
boss.city_value = city_value;
Menu.update();
break;
case 'stockpile':
itemlist.updateData();
var stockpile_value = 0;
for (var item in itemlist) {
if (itemlist[item].type != 'stockpile') continue;
var owned = inventory[item] || 0;
stockpile_value += owned * itemlist[item].price / 2;
}
if (document.getElementsByClassName("upkeep").length > 0)
boss.total_upkeep = document.getElementsByClassName("upkeep")[0].innerHTML.match(/[\d,]+/)[0].replace(/,/g, "");
boss.stockpile_value = stockpile_value;
Menu.update();
break;
case 'jobs':
/* Always update the list of prep objects. It's not too long */
itemlist.updateData();
break;
default:
break;
}
var action;
/* Check the city buildings */
/* The second condition should be always true */
if (boss.city_check == 0 && Page.c_page != 'city') {
action = new Object();
action.page = 'city';
action.message = 'Checking new buildings available...';
action.time = 0;
boss.actions.inventory_city = action;
}
if (boss.stockpile_check == 0 && Page.c_page != 'stockpile') {
action = new Object();
action.page = 'stockpile';
action.message = 'Checking new weapons available...';
action.time = 0;
boss.actions.inventory_stockpile = action;
}
}
/* vim:set tw=80 sts=2 et ft=javascript: */

function Job() {
this.payout_min = 0;
this.payout_max = 0;
this.exp = 0;
this.mobsters = 0;
this.req_items = new Object();
this.prep_items = new Object();
this.payout_items = new Object();
}

function Joblist() {
var obj = eval(GM_getValue('jobs','({})'));
for (var i in obj) {
this[i] = obj[i];
}
}

Joblist.prototype = new Object();

Joblist.prototype.save = function() {
GM_setValue('jobs', this.toSource());
}

Joblist.prototype.updateData = function() {
if (Page.c_page == 'jobs') {
for (var job in this) if (typeof this[job] == 'object') delete this[job];
var header = document.getElementById('app8743457343_content');
var divs = Utils.getElementsByClassName('rowData', header);
for (var i = 0; i < divs.length; i++) {
var div = divs[i];
var job = new Job();
job.prep_items = new Array();
/* Name */
var tmp = div.getElementsByTagName('b')[0];
job.name = tmp.innerHTML;
/* Payout */
tmp = div.innerHTML.match(/Payout:.*\$([0-9,]+) - \$([0-9,]+)/);
if (tmp) {
job.payout_min = parseInt(tmp[1].replace(/,/g,''));
job.payout_max = parseInt(tmp[2].replace(/,/g,''));
}
/* Experience */
tmp = div.innerHTML.match(/Experience: \+(\d+)/);
if (tmp) job.exp = parseInt(tmp[1]);
/* Mobsters */
tmp = div.innerHTML.match(/Mobsters:\&nbsp;(\d+)/);
if (tmp) job.mobsters = parseInt(tmp[1]);
/* Energy */
tmp = div.innerHTML.match(/Energy:\&nbsp;(\d+)/);
if (tmp) job.energy = parseInt(tmp[1]);
/* Requirements */
var jobItems = "\n Requires: ";
var items = Utils.getElementsByXPath('.//a[contains(@href,"#item")]', div);
for (var j = 0; j < items.length; j++) {
/* Item */
tmp = items[j].href;
tmp = tmp.match(/(jobs|stockpile|city)[\/\?a-z_=&0-9]+#(item_\d+)/);
var item_id = tmp[2];
/* Quantity */
tmp = items[j].nextSibling;
if (tmp.tagName == 'SPAN' && (tmp = tmp.innerHTML.match(/\((use |\+)?(\d+)\)/))) {
if (tmp[1] == 'use ') job.prep_items[item_id] = parseInt(tmp[2]);
else if (tmp[1] == '+') job.payout_items[item_id] = parseInt(tmp[2]);
else job.req_items[item_id] = parseInt(tmp[2]);
} else {
job.req_items[item_id] = 1;
}
jobItems += item_id + ", ";
}
/* Id */
tmp = Utils.getElementsByXPath('.//input[@name="jobid"]', div)[0];
this[tmp.value] = job;
if (logLevel >= 3) GM_log("Job added: " + job.name + jobItems);
}
this.save();
}
}

function jobs_exec() {
if (boss.job_income == 'undefined') boss.job_income = 0;
var jobs = new Joblist();
if (Page.c_page == 'jobs') {
jobs.updateData();
} else if (boss.new_level) {
var action = new Object();
action.page = 'jobs';
action.message = "Checking new jobs available...";
action.time = 0;
boss.actions.jobs_check = action;
return;
}
var jobid = boss.preferences.job;
var message;
switch (jobid) {
case 'none':
boss.job_income = 0;
Menu.update();
return;
case 'payout':
jobid = jobs_selectJob(jobs, false);
if (!jobid) message = "You can not perform any job.";
break;
case 'exp':
jobid = jobs_selectJob(jobs, true);
if (!jobid) message = "You can not perform any job.";
break;
default:
/* Check if we can do this job */
if (!jobs_canDoJob(jobs[jobid])) {
message = "You can not perform the job '" + jobs[jobid].name + "'";
jobid = 0;
break;
}
var prepid;
if (prepid = jobs_needPrepJob(jobs, jobid)) {
if (!jobs_canDoJob(jobs[prepid])) {
message = "You can not perform the preparatory job '" + jobs[prepid].name + "' for '" + jobs[jobid].name + "'";
jobid = 0;
break;
} else {
jobs_updateIncome(jobid);
jobid = prepid;
}
} else jobs_updateIncome(jobid);
break;
}

if (!jobid) {
var error = document.getElementById('scripterror');
error.innerHTML = message + "<br /><br />";
if (logLevel >= 3) GM_log(message);
delete boss.actions.jobs;
boss.job_income = 0;
Menu.update();
return;
}

/* Add the action to the list if it's not already there */
var action = new Object();
action.page = 'jobs';
action.message = "Doing " + jobs[jobid].name + "...";
action.func = 'jobs_dojob';
action.params = [jobid, jobs[jobid].name];
var delay;
boss.type == 'Insomniac' ? delay = 240 : delay = 300;
action.time = Page.now + (jobs[jobid].energy - boss.energy) * delay;
if (boss.energy_time) {
action.time -= (action.time - boss.energy_time) % delay;
}
boss.actions.jobs = action;
}

function jobs_updateIncome(jobid) {
if (!jobid) {
boss.job_income = 0;
Menu.update();
return;
}
var jobratio = jobs_payRatio(jobid);
var coeff;
/* Energy per turn */
switch (boss.type) {
/* Turns of 60 minutes, energy 4 minutes */
case 'Insomniac':
coeff = 15;
break;
/* Turns of 54 minutes, energy 5 minutes */
case 'Tycoon':
coeff = 10.8;
break;
/* Turns of 60 minutes, energy 5 minutes */
default:
coeff = 12;
break;
}
if (boss.job_income != Math.floor(coeff * jobratio)) {
boss.job_income = Math.floor(coeff * jobratio);
Menu.update();
}
}

function jobs_canDoJob(job) {
/* Check items */
for (var item in job.req_items) {
if (job.req_items[item] > inventory[item]) {
if (logLevel >= 3) GM_log("Not enough items for " + job.name + ": " + item + " missing");
return false;
}
}
/* Check mobsters */
if (job.mobsters > boss.mobsters + 1) {
if (logLevel >= 3) GM_log("Not enough mobsters for " + job.name);
return false;
}
/* Check maximum energy */
if (job.energy > boss.max_energy) {
if (logLevel >= 1) GM_log("Will never have enough energy for " + job.name);
return false;
}
return true;
}

function jobs_needPrepJob(jobs, jobid) {
for (var item in jobs[jobid].prep_items) {
if (jobs[jobid].prep_items[item] > inventory[item]) {
for (var id in jobs) {
if (jobs[id].payout_items[item]) return id;
}
}
}
return 0;
}

function jobs_payRatio(jobid, jobs) {
if (!jobs) jobs = new Joblist();
var energy = jobs[jobid].energy + 0.0;
for (var item in jobs[jobid].prep_items) {
energy += jobs[jobid].prep_items[item] * itemlist[item].energy_per_unit;
}
energy = (jobs[jobid].payout_min + jobs[jobid].payout_max) / energy;
return energy / 2;
}

function jobs_selectJob(jobs, exp) {
var pay_ratio = 0;
var exp_ratio = 0;
var jobid = 0;
var payed_job = 0;
var tmpid;
var energy;
for (tmpid in jobs) {
if (!jobs[tmpid].name) continue;
var tmpexp_ratio = 0.0 + jobs[tmpid].exp / jobs[tmpid].energy;
var tmppay_ratio = jobs_payRatio(tmpid, jobs);
/* If this job is worse continue with the next */
if (exp) {
if ((tmpexp_ratio < exp_ratio) || (tmpexp_ratio == exp_ratio && tmppay_ratio < pay_ratio)) continue;
} else {
if ((tmppay_ratio < pay_ratio) || (tmppay_ratio == pay_ratio && tmpexp_ratio < exp_ratio)) continue;
}
/* Check if we can do this job */
if (!jobs_canDoJob(jobs[tmpid])) continue;
/* Do we need a prep job? */
var prepid;
if (prepid = jobs_needPrepJob(jobs, tmpid)) {
/* Can we do the job? */
if (!jobs_canDoJob(jobs[prepid])) continue;
else jobid = prepid;
} else jobid = tmpid;

payed_job = tmpid;
pay_ratio = tmppay_ratio;
exp_ratio = tmpexp_ratio;
}
jobs_updateIncome(payed_job);
return jobid;
}

function jobs_dojob(params, timer) {
timer = timer || 5;
/* We want to deposit the money into the bank */
boss.next_pay = 0;
var submit = Utils.getElementsByXPath('//input[@name="jobid" and @value="' + params[0] + '"]/../input[@type="submit"]');
Timer.start(submit[0], "Doing " + params[1] + "...", timer);
}

function jobs_preferencesInterface(prefs) {
if (boss.preferences.job == undefined) boss.preferences.job = 'none';
var jobs = new Joblist();
var div = document.createElement('div');
div.innerHTML = '<label for="joblist">Job to perform: </label>';
var select = document.createElement('select');
var option;
select.name = 'joblist';
option = '<option value="none"';
if (boss.preferences.job == 'none') option += ' selected="selected"';
option += '>None</option><option value="payout"';
if (boss.preferences.job == 'payout') option += ' selected="selected"';
option += '>Best payout/energy</option><option value="exp"';
if (boss.preferences.job == 'exp') option += ' selected="selected"';
option += '>Best experience/energy</option>';
select.innerHTML = option;
for (var job in jobs) {
if (jobs[job].name) {
option = document.createElement('option');
option.value = job;
if (boss.preferences.job == option.value) option.selected = true;
option.innerHTML = jobs[job].name;
select.appendChild(option);
}
}
div.appendChild(select);
prefs.form.insertBefore(div, prefs.button);
}

function jobs_preferencesHandler(form, boss) {
var jobid;
var select = form.elements.namedItem('joblist');
jobid = select.options[select.selectedIndex].value;
if (jobid != boss.preferences.job) {
delete boss.actions.jobs;
boss.preferences.job = jobid;
return true;
}
return false;
}
/* vim:set tw=80 sts=2 et ft=javascript: */

function skill_exec(){
var levelUp = false;
delete boss.actions.skill;
if (boss.preferences.skill == 'none') return;
if (boss.new_level)
levelUp = true;
else {
if (boss.preferences.job == undefined || boss.preferences.job == 'none') return;
var header = document.getElementById('app8743457343_statusMenu');
var str = header.innerHTML;
var re = /Level Up/;
var result = str.match(re);
if (result)
levelUp = true;
}
if (boss.preferences.skill == "recovery_max" && Page.c_page == 'boss'){
var header = document.getElementById('app8743457343_content');
var announcement = Utils.getElementsByClassName('announcement', header)[0].innerHTML;
announcement = announcement.replace(/,/g,'');
var result = announcement.match(/You have <b>?\$?([0-9]+)/);
var points = 0;
if (result)
points = parseInt(result[1]);
if (!(points >= 2))
levelUp = false;
}
if (levelUp) {
var action = new Object();
action.message = "Leveling up...";
action.page = 'boss';
action.func = 'skill_levelUp';
action.params = [];
action.time = 0;
boss.actions.skill = action;
} else {
var action = new Object();
action.message = "Waiting for next level up...";
action.page = 'boss';
action.time = (boss.actions.jobs)? boss.actions.jobs.time + 1 : 3600;
boss.actions.skill = action;
}
}

function skill_levelUp(params, timer){
var obj = Utils.getElementsByXPath('//a[contains(@href, "type=' + boss.preferences.skill + '")]')[0];
var url = obj.href;
Timer.start(url, "Increasing skill...", 3);
}

function skill_preferencesInterface(prefs){
if (boss.preferences.skill == undefined) boss.preferences.skill = 'none';
var div = document.createElement('div');
div.innerHTML = '<label for="skillList">Skill to automatically level up: </label>';
var select = document.createElement('select');
var option;
select.name = 'skillList';
option = '<option value="none"';
if (boss.preferences.skill == 'none') option += ' selected="selected"';
option += '>None</option><option value="attack"';
if (boss.preferences.skill == 'attack') option += ' selected="selected"';
option += '>Attack Strength</option><option value="defense"';
if (boss.preferences.skill == 'defense') option += ' selected="selected"';
option += '>Defense Strength</option><option value="energy_max"';
if (boss.preferences.skill == 'energy_max') option += ' selected="selected"';
option += '>Max Energy</option><option value="health_max"';
if (boss.preferences.skill == 'health_max') option += ' selected="selected"';
option += '>Max Health</option><option value="recovery_max"';
if (boss.preferences.skill == 'recovery_max') option += ' selected="selected"';
option += '>Stamina</option>';
select.innerHTML = option;
div.appendChild(select);
prefs.form.insertBefore(div, prefs.button);
}

function skill_preferencesHandler(form, boss) {
var select = form.elements.namedItem('skillList');
if (boss.preferences.skill != select.options[select.selectedIndex].value) {
boss.preferences.skill = select.options[select.selectedIndex].value;
return true;
}
return false;
}

function bank_exec() {
/* The multiplier compells you to put at least $10,000 the first time */
var multiplier = 1;
if (boss.next_pay == undefined) boss.next_pay = 0;
if (boss.bank_cash == undefined) boss.bank_cash = 0;
/* Value before update */
var next_pay = boss.next_pay;
switch (Page.c_page) {
case 'bank':
var balance = Utils.getElementsByClassName('myBalance')[0];
if (balance) {
var amount = balance.innerHTML.match(/\$([0-9,]+)/)[1];
amount = amount.replace(/,/g, '');
boss.bank_cash = parseInt(amount);
Menu.update();
}
break;
case 'city':
var earnings = Utils.getElementsByClassName('earnings')[0];
if (earnings) {
var time = document.getElementById("app8743457343_cur_cash_countdown").innerHTML;
boss.next_pay = Page.now + (60 * parseInt(time.substr(":"))) + parseInt(time.substr(time.indexOf(":") + 1));
} else boss.next_pay = Page.now + 3600;
break;
case 'hospital':
var header = document.getElementById('app8743457343_content');
header = header.getElementsByTagName('span');
if (header.length) {
header = header[header.length - 1];
header = header.innerHTML.replace(/[\$,]/g,'');
header = parseInt(header);
if (header) boss.bank_cash = header;
Menu.update();
}
break;
default:
break;
}

if (!boss.bank_cash) multiplier = 10;
if (!boss.preferences.bank_active) return;
if (boss.actions.bank || boss.actions.bank_checkpay) return;
if (next_pay < Page.now && boss.cash > 1000 * multiplier) {
var action = new Object();
action.message = "Going to the bank...";
action.page = 'bank';
action.func = 'bank_deposit';
action.params = [];
action.time = 0;
boss.actions.bank = action;
} else {
var action = new Object();
action.message = "Waiting for next payroll...";
action.page = 'city';
action.time = boss.next_pay;
boss.actions.bank_checkdelay = action;
}
}

function bank_deposit(params, timer) {
var submit = Utils.getElementsByXPath('//input[@value="Deposit" or @value="Open Account"]')[0];
var amount = submit.parentNode.elements.namedItem('deposit_amount');
amount.value = boss.cash;
Timer.start(submit, 'Depositing $' + boss.cash + ' into the bank...', 5);
}

function bank_withdraw(params, timer){ // params[0] = amount, params[1] = optional action
//var amount = params[0];
if (logLevel >= 2) GM_log("bank_withdraw: amount= " + params);
var amount = params;
if (document.getElementsByName("withdraw_amount")[0] != null){
var submit = Utils.getElementsByXPath('//input[@value="Withdraw"]')[0];
document.getElementsByName("withdraw_amount")[0].value = amount;
Timer.start(submit, 'Withdrawing $' + amount + ' from the bank...', 5);
}
//if (params[1]) boss.actions.bank_postWithdraw = params[1];
}

function bank_preferencesInterface(prefs) {
if (boss.preferences.bank_active == undefined) boss.preferences.bank_active = false;
var value = boss.preferences.bank_active;
var option = new Array();
option.push('<label for="bank_active">Automatically deposit your money to the bank</label><br />');
if (value) {
option.push('Yes <input type="radio" name="bank_active" value="1" checked="checked"/>');
option.push('No <input type="radio" name="bank_active" value="0"/>');
} else {
option.push('Yes <input type="radio" name="bank_active" value="1"/>');
option.push('No <input type="radio" name="bank_active" value="0" checked="checked"/>');
}
var div = document.createElement('div');
div.innerHTML = option.join('\n');
prefs.form.insertBefore(div, prefs.button);
}

function bank_preferencesHandler(form, boss) {
var input = form.elements.namedItem('bank_active');
if (boss.preferences.bank_active != input.checked) {
delete boss.actions.bank;
delete boss.actions.bank_checkdelay;
boss.preferences.bank_active = input.checked;
return true;
}
return false;
}
/* vim:set tw=80 sts=2 et ft=javascript: */

function hospital_exec() {
if (boss.heal_cost == undefined) boss.heal_cost = 0;
/* If we cannot update the data it means there is not button and we can't
* heal*/
var can_heal = true;
if (Page.c_page == 'hospital') {
if (!hospital_updateData()) {
delete boss.actions.hospital;
can_heal = false;
}
}
if (can_heal && boss.health * 100 < boss.max_health * boss.preferences.heal_limit && boss.bank_cash > boss.heal_cost) {
var action = new Object();
action.message = "Healing...";
action.page = 'hospital';
action.func = 'hospital_heal';
action.params = [];
action.time = 0;
boss.actions.hospital = action;
}
}

function hospital_updateData() {
if (Page.c_page == 'hospital') {
var el = Utils.getElementsByXPath('//input[@type="submit"]')[0];
if (el) {
el = el.value.replace(/,/g,'');
el = parseInt(el.match(/\d+/)[0]);
boss.heal_cost = el;
return true;
} else return false;
}
}

function hospital_heal(params, timer) {
var submit = Utils.getElementsByXPath('//input[@name="action" and @value="heal"]/../input[@type="submit"]')[0];
if (submit) {
Timer.start(submit, 'Healing for $' + boss.heal_cost + '...', 5);
}
}

function hospital_preferencesInterface(prefs) {
if (boss.preferences.heal_limit == undefined) boss.preferences.heal_limit = 0;
if (boss.preferences.heal_limit >= 60) boss.preferences.heal_limit = 60;
var value = boss.preferences.heal_limit;
var option = new Array();
option.push('<label for="heal_limit">Heal your boss when weaker than ');
option.push('<input type="text" name="heal_limit" maxlength="3" size="3" ');
option.push('value="' + value + '"/>');
option.push('% of max health (0 to disable, 60% max)</label>');
var div = document.createElement('div');
div.innerHTML = option.join('\n');
prefs.form.insertBefore(div, prefs.button);
}

function hospital_preferencesHandler(form, boss) {
var input = form.elements.namedItem('heal_limit');
input = parseInt(input.value);
if (boss.preferences.heal_limit != input) {
delete boss.actions.hospital;
if (input >= 0 && input <= 100) {
boss.preferences.heal_limit = input;
}
return true;
}
return false;
}
/* vim:set tw=80 sts=2 et ft=javascript: */

function datadisplay_exec() {
switch (Page.c_page) {
case 'city':
datadisplay_ROR();
case 'stockpile':
var result = Utils.getElementsByXPath('//form[contains(@action,"do.php")]/select');
for (var i = 0; i < result.length; i++) {
var input = document.createElement('input');
input.name = 'qty';
input.type = 'text';
input.setAttribute('maxlength', '3');
input.setAttribute('size', '3');
input.value = result[i].options[0].value;
result[i].parentNode.insertBefore(input, result[i]);
result[i].parentNode.removeChild(result[i]);
}
if (Page.c_page == 'city') break;
case 'fight':
if (!itemlist.item_14) break;
var selection = datadisplay_getFightItems();
var attack = datadisplay_getFightPower('attack', selection);
var defense = datadisplay_getFightPower('defense', selection);
var data = new Array();

var header = document.getElementById('app8743457343_content');
header = header.getElementsByTagName('h1')[0];
header.innerHTML += '<br />';
var span = document.createElement('span');
span.className = 'earnings';
data.push('Attack strength: ' + attack);
data.push(', ');
data.push('Defense strength: ' + defense);
if (Page.c_page == 'stockpile') {
var attack_up = datadisplay_getUpgrade(selection, 'attack');
data.push('<br />');
data.push('Best attack upgrade: ');
switch (attack_up[0]) {
case 0:
data.push('N/A');
break;
case 1:
data.push("1 " + itemlist[attack_up[1]].name + " at " + Math.floor(attack_up[2]) + "$/point");
break;
default:
data.push(attack_up[0] + " " + itemlist[attack_up[1]].name + "s at " + Math.floor(attack_up[2]) + "$/point");
break;
}
var defense_up = datadisplay_getUpgrade(selection, 'defense');
data.push('<br />');
data.push('Best defense upgrade: ');
switch (defense_up[0]) {
case 0:
data.push('N/A');
break;
case 1:
data.push("1 " + itemlist[defense_up[1]].name + " at " + Math.floor(defense_up[2]) + "$/point");
break;
default:
data.push(defense_up[0] + " " + itemlist[defense_up[1]].name + "s at " + Math.floor(defense_up[2]) + "$/point");
break;
}
var total_up = datadisplay_getUpgrade(selection, 'total');
data.push('<br/>');
data.push('Best attack/defense upgrade: ');
switch (total_up[0]) {
case 0:
data.push('N/A');
break;
case 1:
data.push("1 " + itemlist[total_up[1]].name + " at " + Math.floor(total_up[2]) + "$/point");
break;
default:
data.push(total_up[0] + " " + itemlist[total_up[1]].name + "s at " + Math.floor(total_up[2]) + "$/point");
break;
}
var str = datadisplay_getUnused(selection);
if (str.length) {
data.push('<br />');
data.push('Unused items: ');
data.push(str);
}
data.push('<br />');
data.push('Current equipment usage: ' + datadisplay_getDisplayFightItems());
} else {
var size = datadisplay_getMaxMobSize(attack);
data.push(', ');
data.push("Max mob size: " + size);
}
span.innerHTML = data.join('');
header.appendChild(span);
default:
break;
}
}

function datadisplay_getDisplayFightItems() {
var items;
var returnVal = "<br><table>";
var types = ['weapon', 'armor', 'vehicle'];

for (var type = 0; type < types.length; type++) {
var mobsters = boss.mobsters + 1;
var items_left = true;
items = new Object();
for (var i in inventory) {
if (!inventory[i] || !itemlist[i] || itemlist[i].type != 'stockpile' || itemlist[i].stocktype != types[type]) continue;
if (!itemlist[i].attack && !itemlist[i].defense) continue;
items[i] = inventory[i];
}
while (mobsters && items.toSource() != '({})') {
var max_price = 0, item = undefined, best;
/* Select the best equipment */
for (item in items) {
if (itemlist[item].price < max_price) continue;
max_price = itemlist[item].price;
best = item;
}
var qty = Math.min(mobsters, items[best]);
returnVal += "<tr><td width='10px'/><td>" + qty + " " + itemlist[best].name
if (qty > 1)
returnVal += "s";
returnVal += "</td></tr>";
mobsters -= qty;
delete items[best];
}
}
returnVal += "</table>";
return returnVal;
}

function datadisplay_getFightItems() {
var items;
var selection = new Object();
var types = ['weapon', 'armor', 'vehicle'];

for (var type = 0; type < types.length; type++) {
var mobsters = boss.mobsters + 1;
var items_left = true;
items = new Object();
for (var i in inventory) {
if (!inventory[i] || !itemlist[i] || itemlist[i].type != 'stockpile' || itemlist[i].stocktype != types[type]) continue;
if (!itemlist[i].attack && !itemlist[i].defense) continue;
items[i] = inventory[i];
}
while (mobsters && items.toSource() != '({})') {
var max_price = 0, item = undefined, best;
/* Select the best equipment */
for (item in items) {
if (itemlist[item].price < max_price) continue;
max_price = itemlist[item].price;
best = item;
}
var qty = Math.min(mobsters, items[best]);
selection[best] = qty;
if (logLevel >= 3) GM_log("Stockpile selection: " + qty + " " + itemlist[best].name );
mobsters -= qty;
delete items[best];
}
}
return selection;
}

function datadisplay_getFightPower(str, selection) {
var result = 0;
if (str != 'attack' && str != 'defense') return;
str == 'attack' ? result = boss.attack_strength * (boss.mobsters + 1): result = boss.defense_strength * (boss.mobsters + 1);
var item;
for (item in selection) {
result += itemlist[item][str] * selection[item];
}
return result;
}

function datadisplay_getMaxMobSize(attack_strength) {
var types = ['weapon', 'armor', 'vehicle'];
var result = 1 + 3 * (boss.level - 1);
if (logLevel >= 3) GM_log("Max defense strength: " + result);
for (var type = 0; type < types.length; type++) {
var max_price = 0, max_defense = 0;
for (var i in itemlist) {
if (itemlist[i].type != 'stockpile' || itemlist[i].stocktype != types[type]) continue;
/* Select the best equipment for price */
if (itemlist[i].price > max_price && itemlist[i].defense != 0) {
max_price = itemlist[i].price;
max_defense = itemlist[i].defense;
}
}
if (logLevel >= 3) GM_log("Item with defense: " + max_defense);
result += max_defense;
}
return Math.floor(attack_strength / result);
}

function datadisplay_ROR() {
var income = boss.total_income + boss.job_income - boss.total_upkeep;
for (var item in itemlist) {
if (itemlist[item].type != 'city') continue;
/* Dependencies */
var depends = itemlist[item].depends;
if (depends.length) {
depends = Math.floor(itemlist[depends].price * (10 + inventory[depends]) / 10);
} else {
depends = 0;
}
var total_price = depends + Math.floor(itemlist[item].price * (10 + inventory[item]) / 10);
var roi = Math.floor(100000 * itemlist[item].income / total_price + 0.5);
roi = roi / 1000;
var td = Utils.getElementsByXPath('//a[@name="' + item + '"]/../../td[position() = 2]')[0];
var str = '<br/>ROR: ' + roi;
var len = str.length;
while (len < 16) { str += '&nbsp;'; len++; }
/* Inflaction */
var inflaction = 100 * (11 + inventory[item]) / (10 + inventory[item]) - 100;
var turns_inflaction = Math.ceil(inflaction / roi);
/* Turns to purchase (without any money in the bank) */
var turns_purchase = Math.ceil(total_price / income);
var best_qty = 1;
if (turns_purchase <= turns_inflaction) best_qty = 10;
/* Buy by unit and we have enough money */
if (best_qty == 1 && (boss.cash + boss.bank_cash) >= total_price) best_qty = Math.floor((boss.cash + boss.bank_cash) / total_price);
/* Display best qty */
var input = Utils.getElementsByXPath('..//select[@name="qty"]',td)[0];
input.options[0].value = best_qty;
/* Real turns to purchase */
total_price = best_qty * Math.floor(itemlist[item].price * (10 + inventory[item]) / 10);
if (itemlist[item].depends.length) {
depends = itemlist[item].depends;
var am;
best_qty - inventory[depends] >= 0 ? am = best_qty - inventory[depends] : am = 0;
total_price += am * itemlist[depends].price;
}
total_price -= boss.cash + boss.bank_cash;

turns_purchase = Math.ceil(total_price / income);
if (turns_purchase < 0) turns_purchase = 0;
str += 'Turns left: ' + turns_purchase;
var span = document.createElement('span');
span.innerHTML = str;
td.appendChild(span);
}
}

function datadisplay_getUpgrade(selection, type) {
if (type != 'attack' && type != 'defense' && type != 'total') throw new TypeError();
var other;
type == 'attack' ? other = 'defense': other = 'attack';
var types = ['weapon', 'armor', 'vehicle'];
var result = [0, 'item_14', Infinity];
for (var i = 0; i < types.length; i++) {
var left = boss.mobsters + 1;
var power = Infinity, otherpower = Infinity, amount = 0, least;
/* Select the least powerful weapon */
for (var item in selection) {
if (logLevel >= 3) GM_log(item);
if (!itemlist[item]) continue;
if (itemlist[item].stocktype != types[i]) continue;
left -= selection[item];
if (type == 'total' && itemlist[item].attack + itemlist[item].defense < power) {
power = itemlist[item].attack + itemlist[item].defense;
amount = selection[item];
least = item;
} else if (itemlist[item][type] < power || itemlist[item][type] == power && itemlist[item][other] < otherpower) {
power = itemlist[item][type];
otherpower = itemlist[item][other];
amount = selection[item];
least = item;
}
}
if (least && logLevel >= 3) GM_log(type + ": Least powerful " + types[i] + " is " + itemlist[least].name);
/* If there are mobsters that fight barehanded */
if (left) {
power = 0;
amount = left;
least = undefined;
}
/* Select best weapon */
var best = undefined, ratio = Infinity;
for (var item in itemlist) {
if (itemlist[item].type != 'stockpile' || itemlist[item].stocktype != types[i]) continue;

/* Look only for more expensive weapons */
if (least && itemlist[item].price < itemlist[least].price) continue;

var tmpratio;
if (type == 'total') tmpratio = itemlist[item].attack + itemlist[item].defense - power;
else tmpratio = itemlist[item][type] - power;
if (tmpratio > 0) tmpratio = itemlist[item].price / tmpratio;
else continue;
if (tmpratio < ratio) {
ratio = tmpratio;
best = item;
}
}
/* If we can not find a better weapon continue */
if (!best) continue;
if (logLevel >= 3) GM_log(type + ": Selected " + types[i] + " " + itemlist[best].name + " with ratio " + ratio);
/* If this weapon has a better ratio replace it */
if (ratio < result[2]) {
result[0] = amount;
result[1] = best;
result[2] = ratio;
}
}
return result;
}

function datadisplay_getUnused(used) {
var res = new Array();
var amount;
for (var item in itemlist) {
if (itemlist[item].type != 'stockpile') continue;
if (used[item] == undefined) used[item] = 0;
if (amount = (inventory[item] - used[item])) {
res.push(amount + " " + itemlist[item].name + (amount == 1? '': 's'));
}
}
return res.join(', ');
}

GM_registerMenuCommand("Reset Auto City Buy's next purchase",
function() {
boss.autoCityBuy_cost = undefined;
boss.autoCityBuy_item = undefined;
boss.autoCityBuy_UndevelopedLand = undefined;
delete boss.actions.autoCityBuy;
autoCityBuy_exec();
boss.save();
});

function autoGodfather_preferencesInterface(prefs) {
if (boss.preferences.autoGodfather == undefined) boss.preferences.autoGodfather = 'none';
var div = document.createElement('div');
div.innerHTML = '<label for="offerList">Godfather offer to use: </label>';
var select = document.createElement('select');
var option;
select.name = 'offerList';
option = '<option value="none"';
if (boss.preferences.autoGodfather == 'none') option += ' selected="selected"';
option += '>None</option><option value="specialWeapon"';
if (boss.preferences.autoGodfather == 'specialWeapon') option += ' selected="selected"';
option += '>Special Weapon</option><option value="cash"';
if (boss.preferences.autoGodfather == 'cash') option += ' selected="selected"';
option += '>Cash</option><option value="friend"';
if (boss.preferences.autoGodfather == 'friend') option += ' selected="selected"';
option += '>Friend</option><option value="energy"';
if (boss.preferences.autoGodfather == 'energy') option += ' selected="selected"';
option += '>Energy</option><option value="health"';
if (boss.preferences.autoGodfather == 'health') option += ' selected="selected"';
option += '>Health</option><option value="recovery"';
if (boss.preferences.autoGodfather == 'recovery') option += ' selected="selected"';
option += '>Stanima</option><option value="insider"';
if (boss.preferences.autoGodfather == 'insider') option += ' selected="selected"';
option += '>Insider</option>';
select.innerHTML = option;
div.appendChild(select);
prefs.form.insertBefore(div, prefs.button);
}

function autoGodfather_preferencesHandler(form, boss) {
var offer;
var select = form.elements.namedItem('offerList');
offer = select.options[select.selectedIndex].value;
if (offer != boss.preferences.autoGodfather) {
delete boss.actions.autoGodfather;
boss.preferences.autoGodfather = offer;
boss.preferences.autoGodfather_Points = autoGodfather_points(offer);
return true;
}
return false;
}

function autoGodfather_points(offer){
switch(offer){
case "specialWeapon": return 20;
case "cash": return 10;
case "friend": return 10;
case "energy": return 10;
case "health": return 4;
case "recovery": return 10;
case "insider": return 100;
}
}

function autoGodfather_exec(){
if (boss.preferences.autoGodfather == undefined) boss.preferences.autoGodfather = "none";
if (boss.preferences.autoGodfather == "none") return;
var startIndex = document.getElementById("app8743457343_navMenu").innerHTML.indexOf('Godfather <span class="subCounts">(') + 35;
var stopIndex = document.getElementById("app8743457343_navMenu").innerHTML.indexOf(")", startIndex);
var points = parseInt(document.getElementById("app8743457343_navMenu").innerHTML.substring(startIndex,stopIndex));
if (points >= boss.preferences.autoGodfather_Points){
var action = new Object();
action.message = "Cashing in Godfather points...";
action.page = 'godfather';
action.func = 'autoGodfather_cashIn';
action.params = [];
action.time = 3;
boss.actions.autoGodfather = action;
}
if (logLevel >= 2) GM_log("autoGodfather_exec: " + points + " points currently, " + boss.preferences.autoGodfather_Points + " needed for " + boss.preferences.autoGodfather);
}

function autoGodfather_cashIn(){
var rewards = document.getElementsByName("reward");
for (i in rewards){
if (rewards[i].value == boss.preferences.autoGodfather)
rewards[i].form.submit();
}
}

function autoCityBuy_exec(){
if (!boss.preferences.autoCityBuy) return;
if (boss.autoCityBuy_cost == undefined) boss.autoCityBuy_cost = 0;
if (boss.autoCityBuy_item == undefined) boss.autoCityBuy_item = "";
if (logLevel >= 2) GM_log("autoCityBuy_exec: boss.autoCityBuy_cost= " + menu_intToDollars(boss.autoCityBuy_cost)
+ "; boss.autoCityBuy_item= " + boss.autoCityBuy_item);
if (boss.autoCityBuy_cost == 0 || boss.autoCityBuy_item == "") {
if (Page.c_page == 'city') {
autoCityBuy_getBestBuy();
autoCityBuy_exec();
} else {
var action = new Object();
action.message = "Checking next city purchase...";
action.page = 'city';
action.func = 'autoCityBuy_getBestBuy';
action.params = [];
action.time = 3;
boss.actions.autoCityBuy = action;
}
//if (Page.c_page == 'city') document.location.reload();
} else {
var money;
if (boss.preferences.autoCityBuy_withBank && boss.bank_cash > 2000) money = boss.cash + boss.bank_cash - 2000;
else money = boss.cash;
if (boss.autoCityBuy_cost <= money) {
if (boss.autoCityBuy_cost <= boss.cash){
var action = new Object();
action.message = "Buying property...";
action.page = 'city';
action.func = 'autoCityBuy_buyProperty';
action.params = [];
action.time = 3;
boss.actions.autoCityBuy = action;
} else {
var action = new Object();
action.message = "Going to the bank...";
action.page = 'bank';
action.func = 'bank_withdraw';
action.params = boss.autoCityBuy_cost - boss.cash;
action.time = 3;
boss.actions.autoCityBuy = action;
}
} else {
if (logLevel >= 2) GM_log("autoCityBuy_exec: not enough money to buy yet, need "
+ menu_intToDollars(boss.autoCityBuy_cost - money) + " more.");
setTimeout('window.location.reload()', 3600000); // Reload the page after 1 hour (incase nothing else is happening)
}
}
}

function autoCityBuy_getBestBuy(){
if (Page.c_page == 'city'){
boss.autoCityBuy_item = "";
boss.autoCityBuy_cost = 0;
var links = Utils.getElementsByXPath('//a[contains(@name,"item")]');
var selectedRoR = 0;
var money;
if (boss.preferences.autoCityBuy_withBank && boss.bank_cash > 2000) money = boss.cash + boss.bank_cash - 2000;
else money = boss.cash;
for (var i in links){
if (isUndevelopedLand(links[i].name)){
if (inventory[links[i].name] != null && parseInt(inventory[links[i].name]) >= 10) continue;
}
var row = links[i].parentNode.parentNode;
var startIndex = row.innerHTML.indexOf("ROR: ", 0) + 5;
var stopIndex = row.innerHTML.indexOf("&nbsp", startIndex);
var ror = Number(row.innerHTML.substring(startIndex, stopIndex));
if (ror >= selectedRoR){
var span = row.getElementsByTagName("span")[1];
var cost = parseInt(span.innerHTML.replace("$", "").replace(/,/g, "")) * 10;
if (ror == selectedRoR && boss.autoCityBuy_cost > 0 && cost > money && boss.autoCityBuy_cost < money)
continue; // If it is the same RoR as the selected property, only select the most costly one that you can actually afford.
selectedRoR = ror;
boss.autoCityBuy_item = links[i].name;
boss.autoCityBuy_cost = cost;
if (logLevel >= 2) GM_log("autoCityBuy_getBestBuy: RoR = " + selectedRoR + "; Item = " + boss.autoCityBuy_item + "; Cost = " + menu_intToDollars(boss.autoCityBuy_cost));
}
}
}
}

function isUndevelopedLand(name){
if (boss.autoCityBuy_UndevelopedLand == undefined){
if (Page.c_page == 'city'){
var table = document.getElementsByClassName("3col")[0];
var links = table.getElementsByTagName("a");
boss.autoCityBuy_UndevelopedLand = new Array();
for (i in links) boss.autoCityBuy_UndevelopedLand.push(links[i].name);
} else return false;
} else {
if (boss.autoCityBuy_UndevelopedLand.toString().indexOf(name) > -1) return true;
else return false;
}
}

function autoCityBuy_buyProperty(){
if (Page.c_page == 'city'){
var row = document.getElementsByName(boss.autoCityBuy_item)[0].parentNode.parentNode;
Array.forEach(row.getElementsByTagName("INPUT"),function(input){
if (input.name=="qty") input.value = "10";
if (input.value=="Buy") {
if (logLevel >= 2) GM_log("autoCityBuy_buyProperty: Buying " + boss.autoCityBuy_item + " for " + menu_intToDollars(boss.autoCityBuy_cost));
boss.autoCityBuy_item = "";
boss.autoCityBuy_cost = 0;
Timer.start(input, "Buying 10 " + row.getElementsByTagName("B")[0].innerHTML + "s...", 3);
}
});
}
}

function autoCityBuy_preferencesInterface(prefs){
if (boss.preferences.autoCityBuy == undefined) boss.preferences.autoCityBuy = false;
var div = document.createElement('div');
var input = '<input name="autoCityBuyChk" type="checkbox"';
if (boss.preferences.autoCityBuy) input += ' checked="checked>"';
input += '/>';
var input2 = '<input name="autoCityBuyChk2" type="checkbox"';
if (boss.preferences.autoCityBuy_withBank == undefined || boss.preferences.autoCityBuy_withBank) input2 += ' checked="checked>"';
input2 += '/>';
div.innerHTML = '<label for="autoCityBuy">Automatically buy city with best RoR: </label>'
+ input + '<label for="autoCityBuy"> Using money from bank:</label>'
+ input2 + '<br>(bought in groups of 10)';
prefs.form.insertBefore(div, prefs.button);
}

function autoCityBuy_preferencesHandler(form, boss) {
var input = form.elements.namedItem('autoCityBuyChk');
var input2 = form.elements.namedItem('autoCityBuyChk2');
if (boss.preferences.autoCityBuy != input.checked || boss.preferences.autoCityBuy_withBank != input2.checked) {
boss.preferences.autoCityBuy = input.checked;
boss.preferences.autoCityBuy_withBank = input2.checked;
return true;
}
return false;
}

function hitListUser(url, timer){
if (window.location.href != url){
var action = new Object();
action.message = "Hitlisting user...";
action.page = 'hitlist';
action.func = 'hitListUser';
action.params = url;
action.time = 0;
boss.actions.hitlistUser = action;
boss.save();
window.location.href = url;
}
else{
var cost = document.getElementsByName("bounty")[0].value;
if (boss.cash < cost) hitListCurrentUser();
else {
Utils.getElementsByXPath('//form[contains(@action,"do.php")]')[0].submit();
}
}
}

function hitListCurrentUser(){
if (boss.actions.bank_withdraw) delete boss.actions.bank_withdraw;
if (boss.actions.hitlistUser) delete boss.actions.hitlistUser;
var cost = document.getElementsByName("bounty")[0].value;
if (boss.cash < cost){
if ((cost - boss.cash) > boss.bank_cash) return;
var action = new Object();
action.message = "Going to bank...";
action.page = 'bank';
action.func = 'bank_withdraw';
action.params = cost - boss.cash;
action.time = 0;
boss.actions.bank_withdraw = action;
var action2 = new Object();
action2.message = "Hitlisting user...";
action2.page = 'bank';
action2.func = 'hitListUser';
action2.params = window.location.href;
action2.time = 1;
boss.actions.hitlistUserNav = action2;
boss.save();
Timer.start("http://apps.facebook.com/mobwars/bank/", "Going to bank...", 3);
} else hitlistUser(window.location.href, null);
}

function loadXMLString(txt){
try{
parser = new DOMParser();
xmlDoc = parser.parseFromString(txt,"text/xml");
return(xmlDoc);
} catch(e) {return(null)};
}

function quickHeal(){
try{
var health = parseInt(document.getElementById("app8743457343_cur_health").innerHTML);
if(health < (boss.max_health * .6)){
GM_xmlhttpRequest({
method: 'GET',
url: 'http://' + location.host + '/mobwars/hospital/',
headers: {
'User-agent': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6 (.NET CLR 3.5.30729)',
'Host': location.host,
'Referer': 'http://' + location.host + '/mobwars/hospital/',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Cookie': document.cookie
},
onload: function(responseDetails) {
var start = responseDetails.responseText.indexOf("<form method=\"post\" action=\"do.php\"");
var end = responseDetails.responseText.indexOf("</form>", start) + 7;
var form = loadXMLString(responseDetails.responseText.substring(start,end));
var req = "http://" + location.host + "/mobwars/hospital/do.php";
for (i in form.getElementsByTagName("input")){
if (form.getElementsByTagName("input")[i].attributes.getNamedItem("type").value != "submit"){
req += ((i == 0)? "?" : "&") + form.getElementsByTagName("input")[i].attributes.getNamedItem("name").value
req += "=" + form.getElementsByTagName("input")[i].attributes.getNamedItem("value").value
}
}
if (req != "http://" + location.host + "/mobwars/hospital/do.php"){
GM_xmlhttpRequest({
method: 'GET',
url: req,
headers: {
'User-agent': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6 (.NET CLR 3.5.30729)',
'Host': location.host,
'Referer': 'http://' + location.host + '/mobwars/hospital/',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Cookie': document.cookie
},
onload: function(responseDetails) {
var regex = new RegExp('(app8743457343_cur_health"[a-z 0-9\="]+>)([0-9]+)', 'gi');
regex.test(responseDetails.responseText);
var health = RegExp.lastParen;
document.getElementById("app8743457343_cur_health").innerHTML = health;
if(parseInt(health) < (boss.max_health * .6)) quickHeal();
},
onerror: function(responseDetails) {
document.location.reload(true);
}
});
}
},
onerror: function(responseDetails) {
document.location.reload(true);
}
});
}
} catch(e){GM_log("Error in Mobwars Helper healMe:" + e.message);}
}

/* Global variables */
var boss;
var itemlist;

(function() {
var chat = document.getElementsByTagName('iframe');
for (var i=0;i<chat.length;i++) chat[i].parentNode.removeChild(chat[i]);
var exception;

/* Create and update our boss and the stockpile */
try {
boss = new Boss();
itemlist = new Itemlist();
boss.updateData();

/* Populate preferences*/
Preferences.populate(this);
if (logLevel >= 3){
var logString = "\nBoss Data:\n";
for (property in boss){
if (property != "save" && property != "updateData")
logString += "\t" + property + "\t\t\t" + eval("boss." + property) + "\n";
}
GM_log(logString);
}
} catch(ex) { exception = ex;}

/* Init the menu */
try {
Menu.init();
} catch(ex) {
alert("Error while inserting the script's menu.\nLine: " + ex.lineNumber + ", error: " + ex.message);
}

var captcha = Utils.getElementsByClassName('cap');
if (captcha.length){
document.title = "Error: Captcha!";
setTimeout('window.location = "http://apps.new.facebook.com/mobwars/"', 240000);
return;
}

if (document.title == "Facebook | Mob Wars : Error loading page"){
document.location = "http://apps.new.facebook.com/mobwars/" + Page.c_page + "/";
return;
}

if (exception) {
var error = document.getElementById('scripterror');
error.innerHTML = "Error in module 'base' on line " + exception.lineNumber + ": " + exception.message + "<br /><br />";
if (logLevel >= 1) GM_log(error.innerHTML);
Timer.start(window.location.href, 'Trying to recover...', 5);
}

for (var i = 0; i < modules.length; i++) {
if (this[modules[i] + '_exec']) {
try {
now = Date.now();
this[modules[i] + '_exec']();
if (logLevel >= 1) GM_log("*** MODULE " + modules[i] + " took " + (Date.now() - now) + " ms ***");
} catch(ex) {
var error = document.getElementById('scripterror');
error.innerHTML = "Error in module '" + modules[i] + "' on line " + ex.lineNumber + ": " + ex.message + "<br /><br />";
if (logLevel >= 1) GM_log(error.innerHTML);
Timer.start(window.location.href, 'Trying to recover...', 5);
}
}
}

var action = new Object();
var id;
action.time = Infinity;

/* Select an action */
var a = new Array();
for (var i in boss.actions) {
a.push(i);
if (boss.actions[i].time < action.time) {
action = boss.actions[i];
id = i;
}
}

/* Remove action from queue */
if (!id) {
boss.save();
return;
}

var timer;
if (action.time < boss.jail_delay) action.time = boss.jail_delay;
action.time - Page.now > 5 ? timer = action.time - Page.now : timer = 5;

if (Page.c_page != action.page) {
var url = 'http://apps.facebook.com/mobwars/' + action.page + '/';
if (action.url_params) url += '?' + action.url_params;
Timer.start(url, action.message, timer);
if (!action.func) delete boss.actions[id];
} else if (action.func) {
this[action.func](action.params, timer);
delete boss.actions[id];
} else {
/* Should never come here, unless there is a bug */
var message;
timer == 10 ? message = "Reloading page..." : message = action.message;
var url = 'http://apps.facebook.com/mobwars/' + action.page + '/';
if (action.url_params) url += '?' + action.url_params;
Timer.start(url, action.message, timer);
delete boss.actions[id];
}

if (Page.c_page == 'hitlist'){
if (window.location.href.indexOf('add', 0) > 0){
var form = Utils.getElementsByXPath('//form[contains(@action,"do.php")]')[0];
var link = document.createElement('a');
link.addEventListener('click', hitListCurrentUser, false);
link.innerHTML = 'Withdraw money and hitlist this user.';
form.appendChild(link);
}
}
if (GM_getValue("MWHelper_Quickheal", false)) quickHeal();
boss.new_level = 0;
boss.save();
} ) ();
/* vim:set tw=80 sts=2 et ft=javascript: */
/*
try{
if (document.getElementById("TDK_LinksFix") == null){
var tr = document.createElement("tr");
tr.id = "TDK_LinksFix";
var cell;
var pages = new Array("jobs", "city", "stockpile", "fight", "hitlist", "godfather", "mob");
cell = document.createElement("td");
cell.innerHTML = '<a href="http://' + location.host + '/mobwars/">Home</a>';
tr.appendChild(cell);
for (i in pages){
cell = document.createElement("td");
cell.innerHTML = '<a href="http://' + location.host + '/mobwars/' + pages[i] + '/">' + pages[i] + '</a>';
tr.appendChild(cell);
}
document.getElementById("app8743457343_navMenu").firstChild.appendChild(tr);
}
if (document.getElementById("app8743457343_content").firstChild.nextSibling.textContent.indexOf("The Stockpile") > -1){
var div = document.getElementById("app8743457343_content").firstChild.nextSibling.nextSibling.nextSibling;
div.innerHTML = '<a class="" href="http://apps.facebook.com/mobwars/stockpile/?show_type=weapon&amp;_fb_q=1">Weapons</a>';
div.innerHTML += '<a class="" href="http://apps.facebook.com/mobwars/stockpile/?show_type=armor&amp;_fb_q=1">Armor</a>';
div.innerHTML += '<a class="" href="http://apps.facebook.com/mobwars/stockpile/?show_type=vehicle&amp;_fb_q=1">Vehicles</a>';
div.innerHTML += '<a class="" href="http://apps.facebook.com/mobwars/stockpile/?show_type=power_item&amp;_fb_q=1">Power Items</a>';
div.innerHTML += '<a class="lastLink" href="http://apps.facebook.com/mobwars/stockpile/pawn_shop.php?_fb_q=1">Job Loot</a>';
}
} catch(e){GM_log("Error in links fix: " + e.message);}
*/

 
TheDruidsKeeper Scriptwright

Mean Bank Loss:
When you set the script to automatically deposit your money into the bank, this will tell you on average how much cash you loose and include that loss in your hourly total.

- Look for the function "Menu.init = function()" and in there, after where it pushes "Mean job payout", add this line:

menuCode.push('<tr><td>Mean bank loss</td><td id="bankloss_stat" style="color: red; text-align: right;"></td></tr>');

- Look for the function "Menu.update = function()" and in there, after where it does this line:

el.innerHTML = menu_intToDollars(boss.job_income);

add this:

if (boss.preferences.bank_active)
el.innerHTML = menu_intToDollars(Math.round((boss.total_income + boss.job_income - boss.total_upkeep) * .1));
else
el.innerHTML = menu_intToDollars(0);

- Finally, after this line:

total = boss.total_income + boss.job_income - boss.total_upkeep;

add this:

if (boss.preferences.bank_active)
total = total - Math.round(total * .1);

 
TheDruidsKeeper Scriptwright

Skill Module
This adds the ability to set your script to automatically increase a set skill when you graduate a level.

First, look for the line that says this:

/* Modules */
var modules = ['inventory', 'datadisplay', 'bank', 'hospital', 'jobs'];

and change it to this:

/* Modules */
var modules = ['inventory', 'datadisplay', 'bank', 'hospital', 'jobs', 'skill'];

And finally, add these new functions, and that should be it :) Any questions, let me know.

function skill_exec(){
var levelUp = false;
delete boss.actions.skill;
if (boss.preferences.skill == 'none') return;
if (boss.new_level)
levelUp = true;
else {
if ( boss.preferences.job == 'none') return;
var header = document.getElementById('app8743457343_statusMenu');
var divs = Utils.getElementsByClassName('wrap3outer', header);
for (var i = 0; i < divs.length; i++) {
var str = divs[i].innerHTML;
str = str.replace(/,/g,'');
var re = /Level Up/;
var result = str.match(re);
if (result)
levelUp = true;
}
}
if (boss.preferences.skill == "recovery_max" && Page.c_page == 'boss'){
var header = document.getElementById('app8743457343_content');
var announcement = Utils.getElementsByClassName('announcement', header)[0].innerHTML;
announcement = announcement.replace(/,/g,'');
var result = announcement.match(/You have <b>?\$?([0-9]+)/);
var points = 0;
if (result)
points = parseInt(result[1]);
if (!(points >= 2))
levelUp = false;
}
if (levelUp) {
var action = new Object();
action.message = "Leveling up...";
action.page = 'boss';
action.func = 'skill_levelUp';
action.params = [];
action.time = 0;
boss.actions.skill = action;
} else {
var action = new Object();
action.message = "Waiting for next level up...";
action.page = 'boss';
action.time = (boss.actions.jobs)? boss.actions.jobs.time + 1 : 3600;
boss.actions.skill = action;
}
}
function skill_levelUp(params, timer){
var obj = Utils.getElementsByXPath('//a[contains(@href, "type=' + boss.preferences.skill + '")]')[0];
var url = obj.href;
Timer.start(url, "Increasing skill...", 3);
}
function skill_preferencesInterface(prefs){
if (boss.preferences.skill == undefined) boss.preferences.skill = 'none';
var div = document.createElement('div');
div.innerHTML = '<label for="skillList">Skill to automatically level up: </label>';
var select = document.createElement('select');
var option;
select.name = 'skillList';
option = '<option value="none"';
if (boss.preferences.skill == 'none') option += ' selected="selected"';
option += '>None</option><option value="attack"';
if (boss.preferences.skill == 'attack') option += ' selected="selected"';
option += '>Attack Strength</option><option value="defense"';
if (boss.preferences.skill == 'defense') option += ' selected="selected"';
option += '>Defense Strength</option><option value="energy_max"';
if (boss.preferences.skill == 'energy_max') option += ' selected="selected"';
option += '>Max Energy</option><option value="health_max"';
if (boss.preferences.skill == 'health_max') option += ' selected="selected"';
option += '>Max Health</option><option value="recovery_max"';
if (boss.preferences.skill == 'recovery_max') option += ' selected="selected"';
option += '>Stamina</option>';
select.innerHTML = option;
div.appendChild(select);
prefs.form.insertBefore(div, prefs.button);
}
function skill_preferencesHandler(form, boss) {
var select = form.elements.namedItem('skillList');
if (boss.preferences.skill != select.options[select.selectedIndex].value) {
boss.preferences.skill = select.options[select.selectedIndex].value;
return true;
}
return false;
}

 
TheDruidsKeeper Scriptwright

Fix for the current script
There are a lot of different fixes around for the recent changes to Mob Wars. This was my simple way of fixing it.

Look for this code:

result = str.match(/Energy:&nbsp;(\d+).*\(\+(\d+)\)/);
item.energy_per_unit = result[1] / result[2];

and change it to this:

result = str.match(/Energy:&nbsp;(\d+).*\(\+(\d+)\)/);
if (result != null)
item.energy_per_unit = result[1] / result[2];
else
item.energy_per_unit = 15;

Then look for this text: "Update the number of items that we have", a few lines below that you will see this:

var div = divs[i].parentNode.parentNode;

and insert these lines below it:

var isPrepJob = div.innerHTML.match(/dojob/);
if (Page.c_page == 'jobs' && isPrepJob == null) div = divs[i].parentNode.parentNode.parentNode.parentNode.parentNode.parentNode;

 
Fiord User

DruidsKeeper,

Like I said before you are the man. After you made the level up feaure I asked about life has been nice when going out of town. Once again kudos to you.

PS.....
I'm surprised someone hasn't asked you to throw the script up here so they could easily install everything without all the editing. I've actually become fond of all the editing.

Again kudos to you dude

 
Keleas User

Thanks ;)

You forgot the one showing what your mob is fighting with as well.

 
TheDruidsKeeper Scriptwright

Fighting Items
This mod will display the items that your mob fights with on the stockpile page.

Add this to the "function datadisplay_exec()" near the bottom, right above "span.innerHTML = data.join('');":

data.push('<br />');
data.push('Current equipment usage: ' + datadisplay_getDisplayFightItems());

And then added this whole new function:

function datadisplay_getDisplayFightItems() {
var items;
var returnVal = "<br><table>";
var types = ['weapon', 'armor', 'vehicle'];
for (var type = 0; type < types.length; type++) {
var mobsters = boss.mobsters + 1;
var items_left = true;
items = new Object();
for (var i in inventory) {
if (!inventory[i] || !itemlist[i] || itemlist[i].type != 'stockpile' || itemlist[i].stocktype != types[type]) continue;
if (!itemlist[i].attack && !itemlist[i].defense) continue;
items[i] = inventory[i];
}
while (mobsters && items.toSource() != '({})') {
var max_price = 0, item = undefined, best;
/* Select the best equipment */
for (item in items) {
if (itemlist[item].price < max_price) continue;
max_price = itemlist[item].price;
best = item;
}
var qty = Math.min(mobsters, items[best]);
returnVal += "<tr><td width='10px'/><td>" + qty + " " + itemlist[best].name
if (qty > 1)
returnVal += "s";
returnVal += "</td></tr>";
mobsters -= qty;
delete items[best];
}
}
returnVal += "</table>";
return returnVal;
}

 
TheDruidsKeeper Scriptwright

I thought I was forgetting something :) I'm surprised too that no one has asked for a full script post, but I think editing the script is more fun anyway.

 
willrocker User

I must say that i would be very grateful if you could post the new version :) by the way i am currently using the 'enhanced' + version, this fixes some of the bugs, eg i couldn't do the liquer smuggling mission, as there was an error! and thanks for the create invites :O what a script i have 234 mobsters at the moment :)

 
plaguez User

Surprise over! can you make a full install script? LOL! Great job on the fixes, you da man!

 
TheDruidsKeeper Scriptwright

I dont know man... giving the full script takes the fun out of it ;) try following the steps and if you have trouble: ask

 
Keleas User

Actually Druids, I would've asked you to make a full script, and keeping it up-to-date with all your edits because i just love them too much =P but I thought it might be too much work for you so i just asked you to post the edits.

 
TheDruidsKeeper Scriptwright

lol, ok.. I'll attach the whole script for the easy installation.

 
ampao User

How do you add the captcha script to the mods you already have?

I got the helper+, but want to add your script onto mine. Or should I just download your script and replace the other one in entirety?

Thanks!

 
TheDruidsKeeper Scriptwright

My "captcha" script really wasn't much of anything...

Near the bottom of the script there was already this:

var captcha = Utils.getElementsByClassName('cap');

and i don't remember what it did after it, but this is what I set it to do now:

if (captcha.length){
document.title = "Error: Captcha!";
return;
}

I did that just so that I could see it on the task bar telling me that I had to enter the captcha.
You could change it to do alert("Error: Captcha!") instead of just changing the title if you want.

 
TheDruidsKeeper Scriptwright

Withdraw to Hitlist
Doesn't it just suck when you want to hitlist someone and you have to write down how much it costs,
then withdraw the money and find that user again to do it?
This mod will add a link you can click on next to the add to hitlist button that will do it
automatically for you :)

Add these new functions:

function hitListUser(url, timer){
if (window.location.href != url){
var action = new Object();
action.message = "Hitlisting user...";
action.page = 'hitlist';
action.func = 'hitListUser';
action.params = url;
action.time = 0;
boss.actions.hitlistUser = action;
boss.save();
window.location.href = url;
}
else{
var cost = document.getElementsByName("bounty")[0].value;
if (boss.cash < cost) hitListCurrentUser();
else {
Utils.getElementsByXPath('//form[contains(@action,"do.php")]')[0].submit();
}
}
}
function hitListCurrentUser(){
if (boss.actions.bank_withdraw) delete boss.actions.bank_withdraw;
if (boss.actions.hitlistUser) delete boss.actions.hitlistUser;
var cost = document.getElementsByName("bounty")[0].value;
if (boss.cash < cost){
if ((cost - boss.cash) > boss.bank_cash) return;
var action = new Object();
action.message = "Going to bank...";
action.page = 'bank';
action.func = 'bank_withdraw';
action.params = cost - boss.cash;
action.time = 0;
boss.actions.bank_withdraw = action;
var action2 = new Object();
action2.message = "Hitlisting user...";
action2.page = 'bank';
action2.func = 'hitListUser';
action2.params = window.location.href;
action2.time = 1;
boss.actions.hitlistUserNav = action2;
boss.save();
Timer.start("http://apps.facebook.com/mobwars/bank/", "Going to bank...", 3);
} else hitlistUser(window.location.href, null);
}
function bank_withdraw(amount, timer){
if (document.getElementsByName("withdraw_amount")[0] != null){
var submit = Utils.getElementsByXPath('//input[@value="Withdraw"]')[0];
document.getElementsByName("withdraw_amount")[0].value = amount;
Timer.start(submit, 'Withdrawing $' + amount + ' from the bank...', 5);
}
}

And then add this to the bottom of the script, just above "boss.new_level = 0;":

if (Page.c_page == 'hitlist'){
if (window.location.href.indexOf('add', 0) > 0){
var form = Utils.getElementsByXPath('//form[contains(@action,"do.php")]')[0];
var link = document.createElement('a');
link.addEventListener('click', hitListCurrentUser, false);
link.innerHTML = 'Withdraw money and hitlist this user.';
form.appendChild(link);
}
}

 
Yoshe User

Druids, maybe I did something wrong, but the full script you posted isn't working for me.
I don't get any 'Total' (It displays $0), nor do I get any values for 'Mean job payout', and
'Mean bank loss' which both display $0. All I did was copy the script you posted and pasted
it into my editor replacing the old one I had and saved it. I am new to this so forgive me,
and thanks for the help.

 
TheDruidsKeeper Scriptwright

@Yoshe
The only suggestion I have is to try copy / pasting it again. I just copied the script from the page myself to see if it worked and it came out perfect for me.
Make sure you delete the entire content of your current script before pasting, and make sure you copy the entire script in the first post here.

EDIT
See my next post below... sorry

 
akaenko User

@TheDruidsKeeper

Doesn't work for me too...

When I Reset MobWars' script database...

I Click Home and it goes ...
Checking name and type of your boss
Checking attack parameters of your boss
Checking new jobs available...
Resting...

No auto going to stockpile or bank ...

Script Preferences
Does not include jobs in this run ...

After I click Stockpile
Checking new jobs available...
Resting...

Now I have all Jobs in Script Preferences

I Select only
Illegal Weapons Smuggling

(I own 1 Aquire Illegal Weapons)
LOG JOBS
http://userscripts.org/users/49912/Facebook MobWars Helper: You have 1 of item_45
(I own 10 Tactical Shotguns)
LOG STOCKPILE
http://userscripts.org/users/49912/Facebook MobWars Helper: You have 10 of item_59

When I select "Illegal Weapons Smuggling"
I have only
Resting...

With or without Enough energy

If I manualy click other navMenu buttons like city, bank, ... It pushes $ amounts to menuCode OK

but

Mean job payout stays $0

It goes:
You can not perform the job 'Drug Smuggling By Air'
because i don't have airplanes ...

You can not perform the job 'Drug Smuggling by Sea'
because i don't have yacht ...

Great Train Robbery
Resting... (no error message)

Illegal Weapons Smuggling
Resting... (no error message)

and I have all things i need ... even prep job done

 
TheDruidsKeeper Scriptwright

My apologies once again...
The script wasn't posting right because I wasn't accounting for &nbsp; being shown as a white space. I'll try and remember that in the future.
It's fixed now.

 
akaenko User

Thanks,

looks like it works now, still ...

When you reset script data it does not go through Stockpile or City for me ...

Checking name and type of your boss
Checking attack parameters of your boss
Checking new jobs available...
Resting...

After I have manualy clicked stockpile it returned me to Jobs and I had all jobs
after that it works fine for me

there are jobs that i don't do that require city stuff, so it would be cool to add loop through city and stockpile in the first run ...

I think that Mobwars Helper + has that feature ...

after that first loop through pages it will have all data and it should work just fine ... Looks that way now ;)

Thanks ... great modification :-)

 
TheDruidsKeeper Scriptwright

You're right, it doesn't go to those pages since the script originally didn't, and I never modded it to do so since I never reset my data. If you want me to add in a mod to do it I can.

 
akaenko User

Could be nice for new users, but the script works great now :)

great job ! thank you !

 
TheDruidsKeeper Scriptwright

Fix for Header
This is my quick fix for the header since they changed it during the night.
I dont have time to fix it the way I would like, but this will work just fine in the mean time.

Look for this line:

var re = /(Cash|Health|Energy|Stamina|Exp|Level): ?\$?([0-9]+)\/?([0-9]+)?/;

That's the code that is mostly invalid now..
So follow the code down until you see this:

default:
alert("Unknown field: " + str);
}
}

And put this after it:

this.cash = parseInt(document.getElementById("app8743457343_cur_cash").innerHTML.replace(/,/g, "").replace("$", ""));
  this.health = parseInt(document.getElementById("app8743457343_cur_health").innerHTML.replace(/,/g, "").replace("$", ""));
  var mystring = document.getElementById("app8743457343_cur_health").parentNode.innerHTML;
  var re2 = /\/([0-9]+)/;
  var foo = mystring.match(re2);
  this.max_health = parseInt(foo[1]);
  this.stamina = parseInt(document.getElementById("app8743457343_cur_recovery").innerHTML.replace(/,/g,"").replace("$", ""));
  mystring = document.getElementById("app8743457343_cur_recovery").parentNode.innerHTML;
  foo = mystring.match(re2);
  this.max_stamina = parseInt(foo[1]);
  this.energy = parseInt(document.getElementById("app8743457343_cur_energy").innerHTML.replace(/,/g, "").replace("$", ""));
  mystring = document.getElementById("app8743457343_cur_energy").parentNode.innerHTML;
  foo = mystring.match(re2);
  this.max_energy = parseInt(foo[1]); 

(thanks btoneill for fixing that for me)

 
TheDruidsKeeper Scriptwright

I will modify above post later on to make the fix better, I just don't have time right now.
And yes, this fix is in the full script posted as well (hopefully I posted it right).

The different "max"'s aren't coming out right, sorry.

Cross
Presentational HTML allowed.
Use <code> for inline code and <pre> for code blocks. Use &lt; and &gt; for literal < and >.
We help break paragraphs and link your links.
or cancel