KoL - Sell from Inventory

By tburke Last update Jul 30, 2009 — Installed 117 times. Daily Installs: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

There are 9 previous versions of this script.

// ==UserScript==
// @name           KoL - Sell from Inventory
// @namespace      kol
// @description    Add selling links to mall and inventory.
// @include        http://www*.kingdomofloathing.com/inventory.php*
// @include        http://www*.kingdomofloathing.com/account.php*
// @include        http://www*.kingdomofloathing.com/managestore.php*
// @include        http://www*.kingdomofloathing.com/manageprices.php*
// ==/UserScript==

// ----- Revision History -----
//  1 Initial release. Allow movement of items directly from inventory to mall.
//  2 Added ability to autosell from inventory. Cleaned up "How many?" prompt to allow canceling.
//  3 Fixed autosell bug when only one item is present.
//  4 Added preferences to account menu.
//  5 Added revision history, like a good programmer.
//     Also, updated description to say exactly where preferences are in account menu.
//  6 Add ability to autosell from mall (both on managestore.php and manageprices.php).
//     Also, cleaned up autoselling from inventory, so it doesn't go to the autosell page.
//     Same deal for moving items to the mall.
//     Also, enforce wrapping at 100 characters, so you can actually read things in the code
//     preview window on userscripts.org.
//  7 Bugfix: sale prices with commas no longer display as null.
//     Bugfix: don't try to attach autosell link to items taken from store inventory.
//     Take pwd value straight from webpage, so we don't have to parse it.
//     Use built-in functions to remove items from inventory, so we don't have to refresh.
//     Miscellaneous cleanup and code re-use.
//     Added error messages if item couldn't be traded/sold.
//     Added options to suppress notification of sale prices.
//     Shorten description in favor of a longer description on userscripts.org.
//  8 Refresh charpane after sales.
//  9 Added ability to move items to display case from inventory.
//     Bugfix: preserve prices and limits when autoselling only some of an item from the mall.
// 10 Removed small bit of code used when debugging previous bugfix.
//     Added ability to move items to closet from inventory.

// ----- Known Issues -----
// Using built-in functions kills the item's links. Maybe I'm wrong, but I think the ability to
// keep the content in place when selling items outweighs the odd chance that you'd need to hit
// the links more than once.

var pwd = '';
function $new(tag, attrib, str) {
	var el, key;
	if (attrib||str) {
		el = $new(tag);
		if (attrib) for (key in attrib) switch(key) {
			case 'click': case 'dblclick': case 'change':
				el.addEventListener(key, attrib[key], true); break;
			default: el.setAttribute(key, attrib[key]);
		}
		if (str) el.appendChild(document.createTextNode(str));
		return el;
	} else return document.createElement(tag);
}
function mallSell(item, qty, price, limit, suppressAlert) { GM_xmlhttpRequest({
	method: 'POST',
	url: location.protocol + '//' + location.host + '/managestore.php',
	headers: {'Content-type': 'application/x-www-form-urlencoded'},
	data: 'action=additem&pwd=' + pwd +
		'&qty1=' + qty + '&item1=' + item + '&price1=' + price + '&limit1=' + limit,
	onload: function (d) {
		var r = d.responseText.match(/for sale for [0-9,]+ Meat/i);
		if (r) {
			if (suppressAlert)
				window.location = window.location;
			else if (GM_getValue('notify_mall', true))
				alert('Put up ' + r + ' each.');
			if (unsafeWindow.updateInv) {
				var chg = {}; chg[item] = -qty;
				unsafeWindow.updateInv(chg);
			}
		} else
			alert('Error occurred trying to put item in mall.');
	}
}); }
function autoSell(item, qty) { GM_xmlhttpRequest({
	method: 'POST',
	url: location.protocol + '//' + location.host + '/sellstuff_ugly.php',
	headers: {'Content-type': 'application/x-www-form-urlencoded'},
	data: 'action=sell&pwd=' + pwd + '&quantity=' + qty + '&item=' + item + '&mode=3',
	onload: function (d) {
		var r = d.responseText.match(/for [0-9,]+ Meat/i);
		if (r) {
			if (GM_getValue('notify_auto', true)) alert('Sold ' + r);
			unsafeWindow.top.charpane.location = unsafeWindow.top.charpane.location;
			if (unsafeWindow.updateInv) {
				var chg = {}; chg[item] = -qty;
				unsafeWindow.updateInv(chg);
			}
		} else
			alert('Error occurred trying to sell item.');
	}
}); }
function putInDisplayCase(item, qty) { GM_xmlhttpRequest({
	method: 'POST',
	url: location.protocol + '//' + location.host + '/managecollection.php',
	headers: {'Content-type': 'application/x-www-form-urlencoded'},
	data: 'action=put&pwd=' + pwd + '&howmany1=' + qty + '&whichitem1=' + item,
	onload: function (d) {
		var r = d.responseText.match(/ moved from inventory to case/i);
		if (r) {
			if (GM_getValue('notify_dc', true)) alert(qty + r);
			if (unsafeWindow.updateInv) {
				var chg = {}; chg[item] = -qty;
				unsafeWindow.updateInv(chg);
			}
		} else
			alert('Error occurred trying to put item in display case.');
	}
}); }
function putInCloset(item, qty) { GM_xmlhttpRequest({
	method: 'POST',
	url: location.protocol + '//' + location.host + '/closet.php',
	headers: {'Content-type': 'application/x-www-form-urlencoded'},
	data: 'action=put&pwd=' + pwd + '&howmany1=' + qty + '&whichitem1=' + item,
	onload: function (d) {
		var r = d.responseText.match(/ moved from inventory to closet/i);
		if (r) {
			if (GM_getValue('notify_closet', true)) alert(qty + r);
			if (unsafeWindow.updateInv) {
				var chg = {}; chg[item] = -qty;
				unsafeWindow.updateInv(chg);
			}
		} else
			alert('Error occurred trying to put item in closet.');
	}
}); }
function autoSellFromMall(item, qty, price, limit) {
	// We want to take all, then sell, then replace what's left,
	// so we don't have to do one request per item.
	GM_xmlhttpRequest({
		method: 'GET',
		url: location.protocol + '//' + location.host + '/managestore.php?action=takeall' +
			'&whichitem=' + item + '&pwd=' + pwd,
		onload: function () {
			if (qty === 1 && GM_getValue('auto_on_one', true)) {
				autoSell(item, 1);
				window.location=window.location;
			} else {
				var x = prompt('How many? (Leave blank for all)');
				if (x !== null) {
					if (x === '') x = qty;
					autoSell(item, x);
					if (x < qty) mallSell(item, qty-x, price, limit, true);
					else window.location=window.location;
				}
			}
		}
	});
}
function printSell(el, func, text, desc, price) {
	el.appendChild(document.createTextNode(' '));
	el.appendChild($new('a', {
		href: 'javascript:void("' + desc + '");',
		click: function () {
			var item = this.parentNode.parentNode.getAttribute('id').replace(/i/, '');
			var max = this.parentNode.parentNode.textContent.match(/\((\d+)\)/);
			max = (max === null) ? 1 : max[1];
			if (max === 1 && GM_getValue('auto_on_one', true)) {
				func(item, 1);
			} else {
				var x = prompt('How many? (Leave blank for all)');
				if (x !== null) {
					if (x === '') x = max;
					func(item, x, price);
				}
			}
		}
	}, '[' + text + ']'));
}
switch (window.location.pathname) {
case '/account.php':
	var i, f = unsafeWindow.getObj('invstuff');
	f.appendChild($new('p', null, 'Sell from Inventory Options'));
	f.appendChild(f = $new('div', {class: 'small'}));

	var opts = {
		'auto_on_one': 'Automatically sell if only one item?',
		'mall_link': 'Display mall link?',
		'notify_mall': 'Notify of mall price?',
		'auto_link': 'Display autosell link?',
		'notify_auto': 'Notify of autosale income?',
		'auto_mall': 'Display autosell link in mall?',
		'dc_link': 'Display display case link?',
		'notify_dc': 'Show display case confirmation?',
		'closet_link': 'Display closet link?',
		'notify_closet': 'Show closet confirmation?'
	};
	for (var k in opts) {
		f.appendChild(i = $new('input', {
			id: k,
			type: 'checkbox',
			click: function (k) {
				return function () { GM_setValue(k, this.checked); };
			}(k)
		}));
		i.checked = GM_getValue(k, true);
		f.appendChild($new('label', {for: k}, opts[k]));
		f.appendChild($new('br'));
	}
break;
case '/inventory.php':
	pwd = unsafeWindow.pwd;
	if (GM_getValue('mall_link', true) || GM_getValue('auto_link', true))
		Array.forEach(unsafeWindow.$('td[id]'), function (td) {
			if (td.getAttribute('id').match(/^i/)) {
				var item = td.getAttribute('id').replace(/i/, '');
				if (GM_getValue('mall_link', true))
					printSell(td.lastChild,
						mallSell, 'mall', 'sell in mall');
				if (GM_getValue('auto_link', true))
					printSell(td.lastChild,
						autoSell, 'auto', 'autosell');
				if (GM_getValue('dc_link', true))
					printSell(td.lastChild,
						putInDisplayCase, 'case', 'put in display case');
				if (GM_getValue('closet_link', true))
					printSell(td.lastChild,
						putInCloset, 'closet', 'put in closet');
			}
		});
break;
case '/managestore.php':
	Array.forEach(document.getElementsByTagName('input'), function (i) {
		if (i.getAttribute('name') === 'pwd') pwd = i.getAttribute('value');
	});
	if (GM_getValue('auto_mall', true))
		Array.forEach(document.getElementsByTagName('tr'), function (tr) {
			if (tr.firstChild.firstChild && tr.firstChild.firstChild.tagName &&
			    tr.firstChild.firstChild.tagName === 'IMG' &&
			    !tr.textContent.match('You acquire')) {
				var item = tr.innerHTML.match(/whichitem=(\d+)/);
				item = item[1];
				var qty = tr.childNodes[1].textContent.match(/\((\d+)\)/);
				var price = tr.childNodes[2].textContent.replace(/[^0-9]/g, '');
				var limit = tr.childNodes[3].textContent.replace(/[^0-9]/g, '');
				qty = (qty === null) ? 1 : qty[1];
				tr.lastChild.appendChild(document.createTextNode(' '));
				tr.lastChild.appendChild($new('a', {
					href: 'javascript: void("autosell");',
					click: function () { autoSellFromMall(item, qty, price, limit) }
				})).appendChild($new('font', {size: '1'}, 'autosell'));
			}
		});
break;
case '/manageprices.php':
	Array.forEach(document.getElementsByTagName('input'), function (i) {
		if (i.getAttribute('name') === 'pwd') pwd = i.getAttribute('value');
	});
	if (GM_getValue('auto_mall', true))
		Array.forEach(document.getElementsByTagName('tr'), function (tr) {
			if (tr.childNodes[4] && tr.childNodes[4].firstChild &&
			    tr.childNodes[4].firstChild.tagName &&
			    tr.childNodes[4].firstChild.tagName === 'INPUT') {
				var item = tr.childNodes[4].firstChild.name.replace('price', '');
				var qty = parseInt(tr.childNodes[1].textContent);
				var price = parseInt(tr.childNodes[4].firstChild.value);
				var limit = parseInt(tr.childNodes[5].firstChild.value);
				tr.appendChild($new('td')).appendChild($new('a', {
					href: 'javascript: void("autosell");',
					click: function () { autoSellFromMall(item, qty, price, limit); }
				}, 'autosell'));
			}
		});
break;
}