Merchant Example Code Description
Goblin Guy (Ron)
- Location: Wizards Crib -- Left of Main map , Main Area
- Donate: 1M Gold == 3.2M Exp (3.2 gold/exp)
Code
Interactive Merchant Mode
if (character.map == "main") { smart_move("mansion") } else { smart_move("main") }
function destroy(inventoryIndex, itemQuantity=1) {
// take an inventory index and optional quantity and
// emit a socket event to destroy the item(s)
// invalid inventory index
// Note: probably not needed if the server does the check anyway
// though there may be value in reducing latency overhead by checking
// here on the client
if (inventoryIndex < 0 || inventoryIndex > 41) return;
// !NaN => true; valid number required
if (!parseInt(itemQuantity)) return;
// quantity must be between 1 and 9999
if (itemQuantity < 1 || itemQuantity > 9999) return;
// define what we're destroy & how many
let destroyPayload = {
num: inventoryIndex,
q: itemQuantity,
statue: true,
}
// emit the destruction of the item
parent.socket.emit("destroy", destroyPayload);
}
//var destroyItemID = locate_item("wbreeches");
//destroy(destroyItemID)
//var potion = locate_item("mpot0");
//send_item("LordAsneeze", potion, 9999)
Go To "X" Camp
// spooky forest snakes
smart_move({ x: 267 , y: -702, map: 'halloween'})
// Ponty/Mainmap
smart_move({ x: -3 , y: -3, map: 'main'})
if (character.map == "main") { smart_move("mansion") } else { smart_move("main") }
Get Items from Bots (Comm)
// move all items to Merch
// Purposely NOT transfering up to slot 41 (Trackatrix slot)
for (let i = 0; i < 40; i++) { send_item("LordAjew", i, 9999); }
// send gold
send_gold("LordAjew", 11800000)
// Move item on bots from first to last
swap(0,41)
var potion = locate_item("mpot0");
send_item("LordAsneeze", potion, 9999)
Merchant booth auto open/close
- You get merchant exp for having booth open periodically so this lets you leave it open but still run around.
- Must be in an interval check so it keeps checking / triggering
// Every second example
setInterval(function(){
if (character.ctype === "merchant" && is_moving(character) && character.stand) close_stand();
if (character.ctype === "merchant" && !is_moving(character) && !character.stand) open_stand();
},1000);
Lazy mine (once)
- Will move to tunnel and mine until it mines, cooldown after you get a fragment is 7440 seconds (2 hours 4 minutes)
// Go to the wall
await smart_move({ x: -264 , y: -195, map: 'tunnel'})
setInterval(function(){
use_hp_or_mp();
if (character.ctype === "merchant" && !is_moving(character) && can_use("mining") && character.mp > 119) {
set_message("mining");
use_skill("mining");
}
},1000);
Lazy upgrade
// Item in 0
// Upgrade scroll in 1
for (let i = 0; i < 7; i++) {
if (can_use("massproduction")) use_skill("massproduction")
await upgrade(0,1);
}
Lazy Exchange
// Item in 0
for (let i = 0; i < 999; i++) {
await exchange(0);
}
Auto Exchange
var eItem = false; //Enable exchanging of items = true, Disable exchanging of items = false
var whitelist = []; //whitelist is for the exchanging of items
setInterval(function() {
//exchanges items in whitelist
if (eItem) {
exchangeItem()
}
}, 1000 / 4); //Loop every 1/4 seconds.
function exchangeItem() {
for (let i = 0; i < character.items.length; i++) {
let c = character.items[i];
if (c) {
if (c && whitelist.includes(c.name)) {
exchange(i)
parent.e_item = i;
}
}
}
}
Auto Sell
var sItem = false; //Enable selling of items = true, Disable selling of items = false
var whitelist = []; //whitelist is for the selling of items
setInterval(function() {
//sells items in whitelist
if (sItem) {
sellItem()
}
}, 1000 / 4); //Loop every 1/4 seconds.
function sellItem() {
for (let i = 0; i < character.items.length; i++) {
let c = character.items[i];
if (c) {
if (c && whitelist.includes(c.name)) {
sell(i);
}
}
}
}
Auto Compound
var whitelist = ['wbook0', 'intamulet', 'stramulet', 'dexamulet', 'intearring', 'strearring', 'dexearring', 'hpbelt', 'hpamulet', 'ringsj', 'amuletofm', 'orbofstr', 'orbofint', 'orbofres', 'orbofhp'];
var use_better_scrolls = false; //240,000 Gold Scroll = true [only will use for +2 and higher], 6,400 Gold Scroll = false [will only use base scroll no matter what]
var maxLevel = 3;
//compound settings
if (enableCompound) {
setInterval(async function() {
//Compound Items
await compound_items();
}, COMPOUND_TIMEOUT);
}
async function compound_items() {
let to_compound = character.items.reduce((collection, item, index) => {
if (item && item.level < maxLevel && whitelist.includes(item.name)) {
let key = item.name + item.level;
!collection.has(key) ? collection.set(key, [item.level, index]) : collection.get(key).push(index);
}
return collection;
}, new Map());
for (var c of to_compound.values()) {
let scroll_name = use_better_scrolls && c[0] > 1 ? 'cscroll1' : 'cscroll0';
for (let i = 1; i + 2 < c.length; i += 3) {
let [scroll, _] = find_item(i => i.name == scroll_name);
if (scroll == -1) {
parent.buy(scroll_name);
return;
}
parent.socket.emit('compound', {
items: [c[i], c[i + 1], c[i + 2]],
scroll_num: scroll,
offering_num: null,
clevel: c[0]
});
}
}
}
function find_item(filter) {
for (let i = 0; i < character.items.length; i++) {
let item = character.items[i];
if (item && filter(item))
return [i, character.items[i]];
}
return [-1, null];
}
Auto Upgrades
var emaxlevel = 7; //Max level it will stop upgrading items at if enabled
var whitelist = ['wgloves', 'wbreeches',];
if(enableUpgrades) {
setInterval(async function() {
await upgrade(emaxlevel);
}, UPGRADE_TIMEOUT);
}
async function upgrade(level) {
set_message("UPGRADING");
for (let i = 0; i < character.items.length; i++) {
let c = character.items[i];
if (c && whitelist.includes(c.name) && c.level < level) {
let grades = get_grade(c);
let scrollname;
if (c.level < grades[0])
scrollname = 'scroll0';
else if (c.level < grades[1])
scrollname = 'scroll1';
else
scrollname = 'scroll2';
let [scroll_slot, scroll] = find_item(i => i.name == scrollname);
if (!scroll) {
parent.buy(scrollname);
return;
}
parent.socket.emit('upgrade', {
item_num: i,
scroll_num: scroll_slot,
offering_num: null,
clevel: c.level
});
return;
}
}
}
function get_grade(item) {
return parent.G.items[item.name].grades;
}
// Returns the item slot and the item given the slot to start from and a filter.
function find_item(filter) {
for (let i = 0; i < character.items.length; i++) {
let item = character.items[i];
if (item && filter(item))
return [i, character.items[i]];
}
return [-1, null];
}
Mining / Fishing (Autonomous)
if(autoMineFish) {
var hasRod = locate_item("rod");
var hasPick = locate_item("pickaxe");
var mainhand = character.slots.mainhand?.name;
// Fishing/Mining Check
// If you can mine, go mine
// If you can fish, go fish
// If you've done both, park ass in main for ponty/upgrade/combines
setInterval(async function(){
if(can_use("mining") && hasPick != -1 || mainhand === "pickaxe") {
set_message("mining");
custom_log("mining");
do_action("mining");
}
if(can_use("fishing") && !can_use("mining") && hasRod != -1 || mainhand === "rod") {
set_message("Fishing");
custom_log("Fishing");
do_action("fishing");
}
if(!can_use("mining") && !can_use("fishing")) {
set_message("Fished/Mined");
custom_log("Fished/Mined");
await smart_move({ x: -3 , y: -3, map: 'main'})
}
if(!can_use("fishing") && can_use("mining") && hasPick === -1) {
set_message("Fished, No Pickaxe");
custom_log("Fished, No Pickaxe");
await smart_move({ x: -3 , y: -3, map: 'main'})
}
if(!can_use("mining") && can_use("fishing") && hasRod === -1) {
set_message("Mined, No Rod");
custom_log("Mined, No Rod");
await smart_move({ x: -3 , y: -3, map: 'main'})
}
// Needs to check if you have either tool EQUIPPED OR in inventory
if(can_use("mining") && can_use("fishing") && hasRod === -1 && hasPick === -1 && mainhand != "pickaxe" && mainhand != "rod") {
set_message("No Tools!");
custom_log("No Tools!");
await smart_move({ x: -3 , y: -3, map: 'main'})
}
},1000 * 60);
}
/*
* DO_ACTION // FISH / MINING
*/
function do_action(action) {
if (IGNORE_ACTION) return
// dont do if there's something else going on
//if (!action || this.current_action || smart.moving)
if (!action || smart.moving)
return;
// don't do anything while it's on cooldown
if (is_on_cooldown(action)) {
return;
}
// what to equip per skill
let item_map = {
fishing: "rod",
mining: "pickaxe"
}
// where to go
let location_map = {
fishing: {map: 'main', x: -1368, y: -216},
mining: {map: 'tunnel', x: -280, y: -26}
}
let location = location_map[action]
set_current_action(action);
smart_move(location)
.then(
(success) => {
custom_log("got to destination")
// turn on current action
set_current_action(action);
let itemName = item_map[action]
let itemIndex = locate_item(itemName)
if (!character.slots.mainhand || !(character.slots.mainhand.name == itemName));
equip(itemIndex)
custom_log("Equip Item: "+itemIndex);
doAction(action);
},
(failure) => {
custom_log(`Couldn't go ${action}`);
}
)
}
function set_current_action(action) {
var currentAction = action;
set_message("Set Action"+action);
}
function clear_current_action(action) {
set_message("Clear Action"+action);
var currentAction = "none";
}
const doAction = (action) => {
set_message("Action:"+ action);
if(character.mp < 119) {
//close.stand();
use_hp_or_mp();
}
if (is_on_cooldown(action)) {
clear_current_action(action);
unequip("mainhand");
if (quantity("broom")) {
equip(locate_item("broom"));
}
return;
}
if (!character.c[action]) {
use_skill(action);
}
// item broke
if (!character.slots.mainhand) {
custom_log("Tool broke: " + itemName);
clear_current_action(action);
}
setTimeout(() => doAction(action), parent.character.c[action]?.ms ?? 1000);
}
/////////// END do_action / Mining/Fishing
Mass Auto List Items (Non Stackable Stuff)
let sellTimer = null;
function sell_item(itemName, itemPrice, quantity=1) {
quantity = quantity ?? 1;
// locate item index using name
let itemIndex = locate_item(itemName);
log(`index: ${itemIndex}`);
// item doesn't exist in inventory if less than 0
if (itemIndex < 0) return false;
// iterate over character slots, look for trade slots
Object.keys(character.slots).filter(key => key.includes("trade")).forEach( (key, tradeIndex) => {
// trade slots start at 1, e.g. trade1
tradeIndex += 1;
log(`Key: ${key} and tradeIndex${tradeIndex}`);
// check if there's a slotted item in there
let slottedItem = character.slots[key];
log(`Slotted item: ${slottedItem?.name}`)
// skip if so
if (slottedItem?.name) return;
log(`Putting ${quantity}x item ${itemName} in inventory's spot ${itemIndex} into the trade spot trade${tradeIndex} at the price ${itemPrice}`)
// getting here we have an empty space
trade(itemIndex, tradeIndex, itemPrice, quantity)
})
}
function sellItem(itemName, price) {
// check to see if there's an existing order on the stand
let buyOrderUp = false;
Object.keys(character.slots).filter(key => key.includes("trade")).forEach( key => {
if (key === itemName) {
buyOrderUp = true;
}
});
if (!quantity(itemName)) {
log(`No more ${itemName} in inventory`);
// dont set more timeouts
return;
}
// if there's a buy order, check again in a little bit
if (buyOrderUp) {
// set timer and exit the func
sellTimer = setTimeout(() => {
sellItem(itemName, price)
}, 1000);
return;
}
// the item should exist
result = sell_item(itemName, price)
if (result === false) {
return
}
// start the timer
sellTimer = setTimeout(() => sellItem(itemName, price), 1000);
}
sellItem("lostearring", 1250000)
Example Compounded/Combined Merchant Script
- Pony Buy
- Walk to Gobbo (although he doesn't unlock his list automatically or use the thing to keep it unlocked after disconn)
- Auto Upgrade (with options)
- Auto Compound (with options)
var attack_mode=false
var ENABLE_LOGS=true
var ENABLE_PONTY=true
var PONTY_TIMEOUT=60000 * 2
var enableGoblinCheck=true
var GOBLIN_TIMEOUT=60000 * 2
var DESTROY_13_ENABLED=false
var enableCompound=true
var COMPOUND_TIMEOUT=6000
var enableUpgrades=true
var UPGRADE_TIMEOUT=5000
var ENABLE_BUY_TOOLS=true
var IGNORE_ACTION=false
var autoMineFish=false
var debug=true
var updateBankAPI=true
var sItem = true;
//var currentAction="";
/*
* SELL LIST
*/
var sellWhitelist = ['wbreeches',]; //whitelist is for the selling of items
////////
if(updateBankAPI) {
setInterval(async function() {
//set_message("Bank API Update");
custom_log("Bank API Update");
await smart_move("bank");
await UpdateEarthBank();
await smart_move({ x: -195 , y: -111, map: 'main'});
},500000);
}
// Whip Merchant Booth Out
setInterval(async function(){
var mainhand = character.slots.mainhand?.name;
use_hp_or_mp();
set_message("Booth Check");
var mainhand = character.slots.mainhand?.name;
// If Mainhand is not broom already, or if we're in tunnel, or mining/fishing
//if(mainhand != "broom" || character.map != "tunnel" || currentAction != "fishing" || currentAction != "mining") {
//custom_log(currentAction);
//var broom = locate_item("broom");
//equip(broom);
//}
if (character.ctype === "merchant" && is_moving(character) && character.stand) close_stand();
if (character.ctype === "merchant" && !is_moving(character) && !character.stand) open_stand();
// Faster mining
if(character.map === "tunnel" && mainhand === "pickaxe" && can_use("mining")) {
set_message("Fast mining");
await do_action("mining");
}
},1000);
if(autoMineFish) {
// Fishing/Mining Check
// If you can mine, go mine
// If you can fish, go fish
// If you've done both, park ass in main for ponty/upgrade/combines
setInterval(async function(){
var hasRod = locate_item("rod");
var hasPick = locate_item("pickaxe");
var mainhand = character.slots.mainhand?.name;
if(can_use("mining") && hasPick != -1 || mainhand === "pickaxe") {
set_message("mining");
custom_log("mining");
await do_action("mining");
}
if(can_use("fishing") && !can_use("mining") && hasRod != -1) {
set_message("Fishing");
custom_log("Fishing");
await do_action("fishing");
}
if(mainhand === "rod" && can_use("fishing") && !can_use("mining")) {
set_message("Fishing");
custom_log("Fishing");
await do_action("fishing");
}
if(!can_use("mining") && !can_use("fishing")) {
set_message("Fished/Mined");
custom_log("Fished/Mined");
await smart_move({ x: -3 , y: -3, map: 'main'})
}
if(!can_use("fishing") && can_use("mining") && hasPick === -1) {
set_message("Fished, No Pickaxe");
custom_log("Fished, No Pickaxe");
await smart_move({ x: -3 , y: -3, map: 'main'})
}
//if(!can_use("mining") && can_use("fishing") && hasRod === -1) {
// set_message("Mined, No Rod");
// custom_log("Mined, No Rod");
// await smart_move({ x: -3 , y: -3, map: 'main'})
//}
// Needs to check if you have either tool EQUIPPED OR in inventory
if(can_use("mining") && can_use("fishing") && hasRod === -1 && hasPick === -1 && mainhand != "pickaxe" && mainhand != "rod") {
set_message("No Tools!");
custom_log("No Tools!");
await smart_move({ x: -3 , y: -3, map: 'main'})
}
set_message("Tool Eq Check");
//var mainhand = character.slots.mainhand?.name;
if(mainhand === "rod" || mainhand === "pickaxe") {
custom_log("Unequiping rod/pickaxe");
unequip("mainhand");
}
},1000 * 60);
}
/*
* DO_ACTION // FISH / MINING
*/
function do_action(action) {
if (IGNORE_ACTION) return
// dont do if there's something else going on
//if (!action || this.current_action || smart.moving)
if (!action || smart.moving)
return;
// don't do anything while it's on cooldown
if (is_on_cooldown(action)) {
return;
}
// what to equip per skill
let item_map = {
fishing: "rod",
mining: "pickaxe"
}
// where to go
let location_map = {
fishing: {map: 'main', x: -1368, y: -216},
mining: {map: 'tunnel', x: -280, y: -26}
}
let location = location_map[action]
set_current_action(action);
smart_move(location)
.then(
(success) => {
custom_log("got to destination")
// turn on current action
set_current_action(action);
let itemName = item_map[action]
let itemIndex = locate_item(itemName)
if (!character.slots.mainhand || !(character.slots.mainhand.name == itemName));
equip(itemIndex)
custom_log("Equip Item: "+itemIndex);
doAction(action);
},
(failure) => {
custom_log(`Couldn't go ${action}`);
}
)
}
function set_current_action(action) {
var currentAction = action;
set_message("Set Action"+action);
}
function clear_current_action(action) {
set_message("Clear Action"+action);
var currentAction = "none";
}
const doAction = (action) => {
set_message("Action:"+ action);
if(character.mp < 119) {
//close.stand();
use_hp_or_mp();
}
if (is_on_cooldown(action)) {
clear_current_action(action);
unequip("mainhand");
if (quantity("broom")) {
equip(locate_item("broom"));
}
return;
}
if (!character.c[action]) {
use_skill(action);
}
// item broke
if (!character.slots.mainhand) {
custom_log("Tool broke: " + itemName);
clear_current_action(action);
}
setTimeout(() => doAction(action), parent.character.c[action]?.ms ?? 1000);
}
/////////// END do_action / Mining/Fishing
/// BUY LISTS
let PONTY_BUY_LIST = [];
// add weapons and accessories
PONTY_BUY_LIST.push(...[
"gcape", "bataxe", "lmace",
"xmace", "basher", "broom",
"t2bow", "t3bow", "rapier", "crossbow", "harpybow",
"glolipop", "ololipop",
"wbook0", "wbook1", "wbookhs",
"harbringer", "oozingterror", "blaster",
"fireblade", "dragondagger", "hdagger",
"scythe", "vsword", "vdagger", "vhammer",
"dartgun", "mshield",
"t2quiver", "exoarm",
"lunarmace",
//"wshoes", "wcap", "coat1", "shoes1", "helmet1",
]);
// add accessories
PONTY_BUY_LIST.push(...[
"dexearring", "strearring", "intearring",
"rabbitsfoot", "vring", "solitaire",
"suckerpunch", "ringofluck", "ringhs", "goldring", "zapper", "trigger",
"strbelt", "intbelt", "dexbelt", "sbelt", "mbelt",
"intamulet", "t2intamulet", "t2stramulet", "t2dexamulet",
"vorb", "strring",
"orbofstr", "orbofdex", "orbofint",
"resistancering", "armorring",
"cring", "cearring", "lostearring",
"molesteeth", "mearring",
"snring", "amuletofm", "bfangamulet",
"sanguine", "mpxamulet", "mpxbelt", "northstar",
"talkingskull", "skullamulet", //"stramulet",
"intring","dexring","quiver","intamulet",
"intearring","dexearring", "dexamulet",//'ringsj',
"strring", "warmscarf1", "frozenkey",
]);
// add equipment
PONTY_BUY_LIST.push(...[
"mittens", "supermittens", "angelwings",
"cyber", "glitch", "fury",
//"wcap", "wbreeches", "wshoes", "wattire", "wgloves",
"fcape", "vcape", "stealthcape",
"wingedboots", "ecape",
]);
// add materials to the list
PONTY_BUY_LIST.push(...[
//"spores", "cclaw",
"poison", "ink", "snakefang",
"carrot", "spidersilk",
"bfur", "lotusf", "funtoken",
"leather", "feather0", "feather1",
"drapes", "ascale", "pstem",
"essenceoffrost", //"essenceoffire",
"essenceoflife", "essenceofgreed",
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8",
"beewings", "spores",
"btusk", "bfang", "bwing",
"goldenegg",
"cscale", "cshell", "candy0", "candy1",
// EASTER
"egg0","egg1", "egg2", "egg3","egg4",
"egg5","egg6","egg7","egg8",
]);
// Manual init shit
// has to be after ponty buy list
// This is the stuff that happens depending on where code is init'd
if(character.map === "main") {
smart_move({ x: -195 , y: -111, map: 'main'});
buy_from_ponty();
}
if(character.map === "woffice") {
buy_from_goblin();
smart_move({ x: -195 , y: -111, map: 'main'});
}
function custom_log(message) {
if (!ENABLE_LOGS) return;
log(message)
}
function buy_modifiers_from_npc(npc_name, items_to_buy=[]) {
custom_log(`Buying from: ${npc_name}`);
// not if we're in the bank
if (character.map.startsWith("bank")) return;
// npc_name - ponty or goblin
// items_to_buy - the list of items to look for
let buy_command = {
'secondhands': 'sbuy',
'lostandfound': 'sbuy'
}
// how many spaces available to buy stuff with
let emptySpaces = character.esize - 1;
// set up handler to receive the emit
parent.socket.once(`${npc_name}`, data => {
//if(npc_name === "lostandfound") set("goblinData", data);
for (let d of data) {
// dont buy more stuff if we're full
if (!emptySpaces) {
custom_log("too full skipping")
continue
}
if (["carrotsword","cdragon"].includes(d.name)) continue;
if (d.p) {
custom_log(`${d.name} has modifier: ${d.rid}`)
parent.socket.emit(buy_command[npc_name], {
"rid": d.rid,
...(npc_name === "lostandfound" && {f: true})
}, 1)
emptySpaces -= 1;
}
if (items_to_buy.includes(d.name)) {
parent.socket.emit(buy_command[npc_name], {
"rid": d.rid,
...(npc_name === "lostandfound" && {f: true})
}, 1)
emptySpaces -= 1;
}
if (DESTROY_13_ENABLED) {
let item = G.items[d.name];
if (item?.g < DESTROY_13_THRESHOLD && item?.upgrade) {
if (item?.level < 13) continue;
parent.socket.emit(buy_command[npc_name], {
"rid": d.rid,
...(npc_name === "lostandfound" && {f: true})
}, 1);
}
}
}
});
parent.socket.emit(`${npc_name}`);
}
////////// GOBLIN
async function move_to_goblin() {
set_message("Move Gobbo");
custom_log("Move Gobbo");
await smart_move("woffice");
}
async function move_to_main() {
set_message("Move Main");
custom_log("Move Main");
await smart_move({ x: -3 , y: -3, map: 'main'})
}
function buy_from_goblin(items_to_buy=PONTY_BUY_LIST) {
if (character.map !== "woffice") {
custom_log("not in woffice");
return;
}
if (character.s.hopsickness) {
custom_log("cannot purchase while sick");
return;
}
items_to_buy.push(...["offeringp"])
set_message("Gobbo Check");
buy_modifiers_from_npc("lostandfound", items_to_buy)
}
/// PONTY
function buy_from_ponty(items_to_buy=PONTY_BUY_LIST) {
if (!ENABLE_PONTY) return
if (character.map !== "main") {
custom_log("cannot buy from ponty while not in main map");
return;
}
set_message("Ponty Chk");
buy_modifiers_from_npc("secondhands", items_to_buy)
}
setInterval(function(){
buy_from_ponty();
},PONTY_TIMEOUT);
if(enableGoblinCheck) {
setInterval(async function(){
set_message("Gobbo Proc");
custom_log("Gobbo Proc");
await move_to_goblin();
await buy_from_goblin();
await move_to_main();
},GOBLIN_TIMEOUT);
}
///////////////////////// COMPOUND //////////////////////
var compound_whitelist = ['wbook0', 'intamulet', 'stramulet', 'dexamulet', 'intearring', 'strearring', 'dexearring', 'hpbelt', 'hpamulet', 'ringsj', 'amuletofm', 'orbofstr', 'orbofint', 'orbofres', 'orbofhp', 'dexring', 'intring', 'strring', 'skullamulet', 'dexbelt','ringsj','strbelt','intbelt',//'vitring',
];
var use_better_scrolls = false; //240,000 Gold Scroll = true [only will use for +2 and higher], 6,400 Gold Scroll = false [will only use base scroll no matter what]
var maxLevel = 3;
//compound settings
if (enableCompound) {
setInterval(async function() {
//if(currentAction === "fishing" || currentAction === "mining") return;
set_message("Compounding");
await compound_items();
}, COMPOUND_TIMEOUT);
}
async function compound_items() {
let to_compound = character.items.reduce((collection, item, index) => {
if (item && item.level < maxLevel && compound_whitelist.includes(item.name)) {
let key = item.name + item.level;
!collection.has(key) ? collection.set(key, [item.level, index]) : collection.get(key).push(index);
}
return collection;
}, new Map());
for (var c of to_compound.values()) {
let scroll_name = use_better_scrolls && c[0] > 1 ? 'cscroll1' : 'cscroll0';
for (let i = 1; i + 2 < c.length; i += 3) {
let [scroll, _] = find_item(i => i.name == scroll_name);
if (scroll == -1) {
parent.buy(scroll_name);
return;
}
parent.socket.emit('compound', {
items: [c[i], c[i + 1], c[i + 2]],
scroll_num: scroll,
offering_num: null,
clevel: c[0]
});
}
}
}
function find_item(filter) {
for (let i = 0; i < character.items.length; i++) {
let item = character.items[i];
if (item && filter(item))
return [i, character.items[i]];
}
return [-1, null];
}
/////////////// UPGRADES //////////////////
var emaxlevel = 7; //Max level it will stop upgrading items at if enabled
var whitelist = ['wgloves', 'wbreeches', 'cupid', 'wcap', 'wattire', 'wshoes',
'pants1','gloves1', 'coat1','shoes1', 'helmet1', 'glolipop', 'ecape',];
if(enableUpgrades) {
setInterval(async function() {
if (can_use("massproduction")) use_skill("massproduction")
//if(currentAction === "fishing" || currentAction === "mining") return;
await upgrade(emaxlevel);
}, UPGRADE_TIMEOUT);
}
async function upgrade(level) {
set_message("UPGRADING");
for (let i = 0; i < character.items.length; i++) {
let c = character.items[i];
if (c && whitelist.includes(c.name) && c.level < level) {
let grades = get_grade(c);
let scrollname;
if (c.level < grades[0])
scrollname = 'scroll0';
else if (c.level < grades[1])
scrollname = 'scroll1';
else
scrollname = 'scroll2';
let [scroll_slot, scroll] = find_item(i => i.name == scrollname);
if (!scroll) {
await smart_move({ x: -195 , y: -111, map: 'main'});
parent.buy(scrollname);
return;
}
if (can_use("massproduction")) use_skill("massproduction")
parent.socket.emit('upgrade', {
item_num: i,
scroll_num: scroll_slot,
offering_num: null,
clevel: c.level
});
return;
}
}
}
function get_grade(item) {
return parent.G.items[item.name].grades;
}
// Returns the item slot and the item given the slot to start from and a filter.
function find_item(filter) {
for (let i = 0; i < character.items.length; i++) {
let item = character.items[i];
if (item && filter(item))
return [i, character.items[i]];
}
return [-1, null];
}
/*
* TOOLS
*/
function buy_tool(tool_name) {
for (let slot of Object.keys(character.slots)) {
if (slot.includes("trade") && !character.slots[slot]) {
parent.socket.emit("trade_wishlist",
{
q: 1,
slot: slot,
price: 1000000,
level: 0,
name: tool_name
}
);
set_message("Wishlist Setup");
return;
}
}
}
function check_for_tools() {
let hasRod = false;
let hasPickaxe = false;
let hasRodWish = false;
let hasPickaxeWish = false;
for (let item of character.items) {
if (item?.name == "pickaxe") {
hasPickaxe = true;
}
if (item?.name == "rod") {
hasRod = true;
}
}
for (let slot of Object.keys(character.slots)) {
let item = character.slots[slot];
if (item?.name == "pickaxe") {
hasPickaxeWish = true;
}
if (item?.name == "rod") {
hasRodWish = true;
}
}
if (!hasRod && !hasRodWish) buy_tool("rod");
if (!hasPickaxe && !hasPickaxeWish) buy_tool("pickaxe");
}
if (ENABLE_BUY_TOOLS) {
check_for_tools()
setInterval(check_for_tools, 60000);
}
/*
* SELL STUFF AUTO
*/
setInterval(function() {
//sells items in whitelist
if (sItem) {
sellItem()
}
}, 1000);
function sellItem() {
for (let i = 0; i < character.items.length; i++) {
let c = character.items[i];
if (c) {
if (c && sellWhitelist.includes(c.name)) {
sell(i);
}
}
}
}
/*
* BANK API
*/
const UpdateEarthBank = async () => {
const ALDATA_KEY=escape("YOURKEY");
const url = `https://aldata.earthiverse.ca/bank/${character.owner}/${ALDATA_KEY}`
let bankData = { ...character.bank };
for (let key in bankData) {
let bankSlot = bankData[key];
// remove nulls
if (Array.isArray(bankSlot)) {
bankData[key] = bankSlot.filter(item => item)
}
}
if (!character.stand) {
await open_stand()
}
// stringify the data
data = JSON.stringify({
...bankData,
items47: { ...character.slots }
});
// create our request
settings = {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: data
};
// if response.status == 200, it was successfully updated
fetch(url, settings).then(response => console.log(response))
}
Destroying Stuff (1/1000000 chance at +13)
function destroy(inventoryIndex, itemQuantity=1) {
// take an inventory index and optional quantity and
// emit a socket event to destroy the item(s)
// invalid inventory index
// Note: probably not needed if the server does the check anyway
// though there may be value in reducing latency overhead by checking
// here on the client
if (inventoryIndex < 0 || inventoryIndex > 41) return;
// !NaN => true; valid number required
if (!parseInt(itemQuantity)) return;
// quantity must be between 1 and 9999
if (itemQuantity < 1 || itemQuantity > 9999) return;
// define what we're destroy & how many
let destroyPayload = {
num: inventoryIndex,
q: itemQuantity,
statue: true,
}
// emit the destruction of the item
parent.socket.emit("destroy", destroyPayload);
}
socket.on("destroy", function (data) {
var player = players[socket.id];
var add = "+nc+inv";
data.num = max(0, parseInt(data.num) || 0);
if (!player.items[data.num]) {
return fail_response("no_item", { num: data.num });
}
var item = player.items[data.num];
var name = player.items[data.num].name;
data.q = min(max(parseInt(data.q) || 0, 1), (item && item.q) || 1);
if (item.name == "placeholder") {
return fail_response("item_placeholder", { num: data.num });
}
if (item.l) {
return fail_response("item_locked", { num: data.num });
}
if (item.b) {
return fail_response("item_blocked", { num: data.num });
}
if (item.level != 13) {
consume(player, data.num, data.q);
//player.items[data.num]=player.citems[data.num]=null;
}
if (data.statue) {
if (item.name == "shadowstone") {
add = "+u+cid";
player.s.invis = { ms: 99999 };
}
if (G.items[item.name].upgrade && Math.random() < 1.0 / ((gameplay == "hardcore" && 10000) || 1000000)) { <--- THIS SECTION
add = "+u+cid";
item.level = 13;
player.items[data.num] = item;
player.citems[data.num] = cache_item(player.items[data.num]);
const announce = !item.silent;
if (announce && !player.stealth) {
broadcast("server_message", {
message: player.name + " received " + item_to_phrase(item),
color: colors.server_success,
item: cache_item(item),
type: "server_usuccess",
name: player.name,
});
}
}
xy_emit(G.maps.spookytown.ref.poof, "upgrade", { type: "poof", success: 1 });
}
resend(player, "reopen" + add);
success_response("destroyed", { name: name, num: data.num, cevent: "destroy" });
});
var destroyItemID = locate_item("wbreeches");
destroy(destroyItemID)