Skip to content

Instantly share code, notes, and snippets.

@tokida
Last active October 31, 2020 01:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tokida/7bd74131f3b707989a2d50748af33fb5 to your computer and use it in GitHub Desktop.
Save tokida/7bd74131f3b707989a2d50748af33fb5 to your computer and use it in GitHub Desktop.
Diablo2 Kolbot alternate follower script ( via https://pastebin.com/LnXCQ3ES )
/*
* Follower by kolton
*
* you should set "LocalChat" in mode 2 for all chars:
* Config.LocalChat.Enabled = true; // enable the LocalChat system
* Config.LocalChat.Mode = 2; // 0 = disabled, 1 = chat from 'say' (recommended), 2 = all chat (for manual play)
*
* version: 28.02.2020
*
* silent-automated follower changes:
* - silent follower will check the leader's act and will go to it.
* - when leader makes tp the follower will try to use it and will precast/buff.
* - the follower will go after leader in town, using his tp, and will do town activities (if autoTownChores = true).
* - lines 986-1000 will stop HC chars, in order to allow the loot of their corpses. *** you should avoid the chat commands untill you get successful loot.
* - quiting/ending the game will be done using the random delay Config.QuitListDelay.
* - check the additional commands: b, ancs, ancsoff, ai, map, stash, restart, end, 0, ...
*
* Commands:
*
* Main commands:
* 1 - take leader's tp from town / move to leader's town
* 2 - take leader's tp to town
*
* 3 | town manager
* <charname> 3 |
*
* p | pick items, potions and open containers
* <charname> p |
*
* c | get softcore player corpse
* <charname> c |
*
* s | toggle stop in town near stash. if outside of town followers will make own tp and stop near stash.
* <charname> s |
*
* Attack:
* a | toggle attack
* <charname> a |
*
* aon | attack on
* <charname> aon |
*
* aoff | attack off
* <charname> aoff |
*
* Teleport:
* *** characters without teleport skill will ignore tele command ***
* tele | toggle teleport
* <charname> tele |
*
* tele on | teleport on
* <charname> tele on |
*
* tele off | teleport off
* <charname> tele off |
*
* Skills:
* all skill <skillid> | change skill (refer to sdk\skills.txt)
* <charname> skill <skillid> |
* <class> skill <skillid> | change skill for all characters of certain class *** any part of class name will do *** for example: "sorc skill 36", "zon skill 0", "din skill 106"
*
* Auras:
* all aura <skillid> | change aura for paladins (refer to sdk\skills.txt)
* <charname> aura <skillid> |
*
* Town:
* a2-5 - move to appropriate act (after quest) !NOTE: Disable 'no sound' or game will crash!
* use a2,a3,a4,a5 chat commands after completing the last quest. trying to get next act/town without having wp yet will lead to Connection Interrupted
* talk <npc name> - talk to a npc in town
* ai | toggle anti-idle
* <charname> ai |
* ancs - prepare for ancients quest a5q5, overwrite the config settings with more potions and towncheck restricted
* ancsoff - revert to char config from ancients config. *** or you can use .reload for every follower
* gamble | start gambling
* <charname> gamble |
*
* Misc:
* cow - enter red cow portal
* <charname> cowopen - this command requires the custom ...\CowOpen.js file (https://raw.githubusercontent.com/blizzhackers/documentation/master/kolbot/custom-scripts/CowOpen.js)
*
* <charname> x - teleporter go to desired area and make tp | x = countess , andariel, summoner, duriel, mephisto, chaos, nihlathak(using HoP wp), throne
*
* wp | activate a nearby wp
* <charname> wp |
*
* bo - barbarian precast
* b - refresh buff all followers
*
* tp | make a TP. Needs a TP tome if not using custom libs.
* <charname> tp |
*
* move | move in a random direction based on player position (use if you're stuck by followers)
* m |
* <charname> m |
*
* dist:x - minimum distance to leader. default value 6. you can set it in range 6 - 30
*
* area: ... x: ... y: ... | move to leader position in the same area *** leader should set a key in ToolsThread.js, like case 111: say("area: " + me.area + " x: " + me.x + " y: " + me.y); ***
*
* map | activate mh in the follower windows
* <charname> map | ** you should reload the char config where you don't want to see the already activated mh
*
* reload - reload script instructions. Use only in case of emergency, or after editing character config.
*
* quit | exit game
* <charname> quit |
*
* restart | restart profiles
* <charname> restart |
*
* end | stop follower profile and release the key, after a random delay
* <charname> end |
*
* Communication between 2 teams, 2nd leader is set as follower for the 1st. *** usefull for getting experience when start a new low char(team) helped by 2nd high level team, cause you can change the distance between the teams (10-20).
* say area - the 2nd leader will announce his position
* say x | 2nd leader will repeat the command
* say x y |
*/
function FollowerSilent() {
var i, j, stop, leader, leaderUnit, piece, skill, result, unit, player, coord, map, tick, ai, gold,
commanders = [Config.Leader],
attack = true,
openContainers = true,
classes = ["amazon", "sorceress", "necromancer", "paladin", "barbarian", "druid", "assassin"],
action = "",
charClass = classes[me.classid],
BCDuration = 0,
BCTick = 0,
autoTownChores = true, // automatic town activities after arriving from field/areas
field = false, // variable used in autoTownChores
dist = 6, // distance to leader. It can be changed with chat "dist:x" by leader.
logCharOnExit = true; // log items of the current char before exit
// Override config values
Config.LocalChat.Enabled = true;
Config.LocalChat.Mode = 2;
Config.TownCheck = true;
Config.OpenChests = true;
// Get closer to leader, or other player
this.getCloser = function () {
if (me.inTown) {
return;
}
if (leaderUnit && getDistance(me.x, me.y, leaderUnit.x, leaderUnit.y) <= 65) {
if (getDistance(me.x, me.y, leaderUnit.x, leaderUnit.y) > dist) {
Pather.moveToUnit(leaderUnit, true);
}
} else if (!leaderUnit) {
player = getUnit(0);
if (player) {
do {
if (player.name !== me.name) {
Pather.moveToUnit(player, true);
break;
}
} while (player.getNext());
}
}
};
// Change areas to where leader is
this.checkExit = function (unit, area) {
if (unit.inTown) {
return false;
}
var i, target,
exits = getArea().exits;
for (i = 0; i < exits.length; i += 1) {
if (exits[i].target === area) {
return 1;
}
}
if (unit.inTown) {
target = getUnit(2, "waypoint");
if (target && getDistance(me, target) < 20) {
return 3;
}
}
target = getUnit(2, "portal");
if (target) {
do {
if (target.objtype === area) {
Pather.usePortal(null, null, target);
return 2;
}
} while (target.getNext());
}
// Arcane<->Cellar portal
if ((me.area === 74 && area === 54) || (me.area === 54 && area === 74)) {
Pather.usePortal(null);
return 4;
}
// Arcane<->Canyon of the Magi
if ((me.area === 74 && area === 46) || (me.area === 46 && area === 74)) {
Pather.usePortal(null);
return 4;
}
// Tal-Rasha's tomb->Duriel's lair
if (me.area >= 66 && me.area <= 72 && area === 73) {
Pather.useUnit(2, 100, area);
return 4;
}
// Throne->Chamber
if (me.area === 131 && area === 132) {
target = getUnit(2, 563);
if (target) {
Pather.usePortal(null, null, target);
return 4;
}
}
return false;
};
// Talk to a NPC
this.talk = function (name) {
if (!me.inTown) {
me.overhead("ÿc1Going to talk in town!");
Town.goToTown();
}
if (typeof name === "string") {
name = name.toLowerCase();
} else {
me.overhead("ÿc1No NPC name given.");
return false;
}
var npc, names;
switch (me.act) {
case 1:
names = [NPC.Gheed, NPC.Charsi, NPC.Akara, NPC.Kashya, NPC.Cain, NPC.Warriv];
break;
case 2:
names = [NPC.Fara, NPC.Lysander, NPC.Greiz, NPC.Elzix, NPC.Jerhyn, NPC.Meshif, NPC.Drognan, NPC.Atma, NPC.Cain];
break;
case 3:
names = [NPC.Alkor, NPC.Asheara, NPC.Ormus, NPC.Hratli, NPC.Cain];
break;
case 4:
names = [NPC.Halbu, NPC.Tyrael, NPC.Jamella, NPC.Cain];
break;
case 5:
names = [NPC.Larzuk, NPC.Malah, NPC.Qual_Kehk, NPC.Anya, NPC.Nihlathak, NPC.Cain];
break;
}
if (names.indexOf(name) === -1) {
me.overhead("ÿc1Invalid NPC.");
return false;
}
if (!Town.move(name === NPC.Jerhyn ? "palace" : name)) {
Town.move("portalspot");
me.overhead("ÿc1Failed to move to town spot.");
return false;
}
npc = getUnit(1);
if (npc) {
do {
if (npc.name.replace(/ /g, "").toLowerCase().indexOf(name) > -1) {
npc.openMenu();
me.cancel();
me.overhead("ÿc2Done talking.");
return true;
}
} while (npc.getNext());
}
me.overhead("ÿc1NPC not found.");
Town.move("portalspot");
return false;
};
// Change act after completing last act quest
this.changeAct = function (act) {
var npc, preArea, target;
preArea = me.area;
switch (act) {
case 2:
if (me.area >= 40) {
break;
}
Town.move(NPC.Warriv);
npc = getUnit(1, 155);
if (npc) {
npc.openMenu();
Misc.useMenu(0x0D36);
}
break;
case 3:
if (me.area >= 75) {
break;
}
Town.move("palace");
npc = getUnit(1, 201);
if (npc) {
npc.openMenu();
me.cancel();
}
Town.move(NPC.Meshif);
npc = getUnit(1, 210);
if (npc) {
npc.openMenu();
Misc.useMenu(0x0D38);
}
break;
case 4:
if (me.area >= 103) {
break;
}
if (me.inTown) {
Town.move(NPC.Cain);
npc = getUnit(1, 245);
if (npc) {
npc.openMenu();
me.cancel();
}
Town.move("portalspot");
Pather.usePortal(102, null);
}
delay(1500);
target = getUnit(2, 342);
if (target) {
Pather.moveTo(target.x - 3, target.y - 1);
}
Pather.usePortal(null);
break;
case 5:
if (me.area >= 109) {
break;
}
Town.move(NPC.Tyrael);
npc = getUnit(1, NPC.Tyrael);
if (npc) {
npc.openMenu();
me.cancel();
try {
Pather.useUnit(2, 566, 109);
} catch (a5e) {
}
}
break;
}
delay(2000);
while (!me.area) {
delay(500);
}
if (me.area === preArea) {
me.cancel();
Town.move("portalspot");
print("ÿc1Act change failed.");
return false;
}
Town.move("portalspot");
me.overhead("ÿc8Act change successful.");
if (act === 2) {
me.overhead("Don't forget to talk to Drognan after getting the Viper Amulet!");
}
return true;
};
this.nextArea = function (area) { // only the exceptions from area = ± 1
switch (area) {
case 1:
return [39];
case 2:
return [8];
case 3:
return [9, 17];
case 4:
return [10, 38];
case 6:
return [11, 20];
case 7:
return [12, 26];
case 8:
return [2];
case 9:
return [3, 13];
case 10:
return [4, 5, 14];
case 11:
return [6, 15];
case 12:
return [7, 16];
case 13:
return [9];
case 14:
return [10];
case 15:
return [11];
case 16:
return [12];
case 17:
return [3, 18, 19];
case 18:
return [17];
case 19:
return [17];
case 39:
return [1];
case 40:
return [47, 50];
case 41:
return [55];
case 42:
return [56];
case 43:
return [62];
case 44:
return [65];
case 45:
return [58];
case 46:
return [66, 67, 68, 69, 70, 71, 72];
case 55:
return [41, 59];
case 56:
return [42];
case 57:
return [60];
case 58:
return [45, 61];
case 59:
return [55];
case 60:
return [57];
case 61:
return [58];
case 62:
return [43];
case 65:
return [44];
case 66:
case 67:
case 68:
case 69:
case 70:
case 71:
case 72:
return [46, 73];
case 76:
return [84, 85];
case 78:
return [86, 88];
case 80:
return [92, 94, 95];
case 81:
return [92, 96, 97];
case 82:
return [98, 99];
case 83:
return [100];
case 84:
case 85:
return [76];
case 86:
case 88:
return [78];
case 87:
return [90];
case 89:
return [91];
case 90:
return [87];
case 91:
return [89];
case 92:
return [80, 81];
case 94:
case 95:
return [80];
case 96:
case 97:
return [81];
case 98:
case 99:
return [82];
case 100:
return [83];
case 109:
return [121];
case 111:
return [125];
case 112:
return [126];
case 113:
return [115];
case 115:
return [113, 117];
case 117:
return [127];
case 118:
return [120];
case 120:
return [128]; // 118 is getting C/I for using the exit
case 125:
return [111];
case 126:
return [112];
case 127:
return [117];
case 128:
return [120];
default:
return [];
}
};
this.precast = function () {
Precast.doPrecast(true);
if (me.classid !== 4 || !me.getSkill(155, 0)) {
return true;
}
BCDuration = (20 + me.getSkill(155, 1) * 10 + (me.getSkill(138, 0) + me.getSkill(149, 0)) * 5) * 1000;
BCTick = getTickCount();
return true;
};
this.pickPotions = function (range) {
if (me.dead) {
return false;
}
Town.clearBelt();
while (!me.idle) {
delay(40);
}
var status,
pickList = [],
item = getUnit(4);
if (item) {
do {
if ((item.mode === 3 || item.mode === 5) && item.itemType >= 76 && item.itemType <= 78 && getDistance(me, item) <= range) {
pickList.push(copyUnit(item));
}
} while (item.getNext());
}
pickList.sort(Pickit.sortItems);
while (pickList.length > 0) {
item = pickList.shift();
if (item && copyUnit(item).x) {
status = Pickit.checkItem(item).result;
if (status && Pickit.canPick(item)) {
Pickit.pickItem(item, status);
}
}
}
return true;
};
this.openContainers = function (range) {
var unit, ox, oy,
unitList = [],
containers = ["chest", "loose rock", "hidden stash", "loose boulder", "corpseonstick", "casket", "armorstand", "weaponrack", "barrel", "holeanim",
"roguecorpse", "ratnest", "corpse", "goo pile", "largeurn", "urn", "chest3", "jug", "skeleton", "guardcorpse", "sarcophagus",
"cocoon", "basket", "stash", "hollow log", "hungskeleton", "pillar", "skullpile", "skull pile", "jar3", "jar2", "jar1", "bonechest", "woodchestl",
"woodchestr", "barrel wilderness", "burialchestr", "burialchestl", "explodingchest", "chestl", "chestr", "icecavejar1", "icecavejar2",
"icecavejar3", "icecavejar4", "deadperson", "deadperson2", "evilurn", "tomb1l", "tomb3l", "tomb2", "tomb3", "object2", "groundtomb", "groundtombl", "crate", "tomb"
];
ox = me.x;
oy = me.y;
unit = getUnit(2);
if (unit) {
do {
if (containers.indexOf(unit.name.toLowerCase()) > -1 && unit.mode === 0 && getDistance(me, unit) <= range) {
unitList.push(copyUnit(unit));
}
} while (unit.getNext());
}
while (unitList.length > 0) {
unitList.sort(Sort.units);
unit = unitList.shift();
if (unit) {
Misc.openChest(unit);
Pickit.pickItems();
}
}
return true;
};
this.chatEvent = function (nick, msg) {
if (msg && nick === Config.Leader) {
switch (msg) {
case "tele":
case me.name + " tele":
if (Pather.teleport) {
Pather.teleport = false;
me.overhead("ÿc1Teleport off.");
} else {
Pather.teleport = true;
me.overhead("ÿc2Teleport on.");
}
break;
case "tele off":
case me.name + " tele off":
Pather.teleport = false;
me.overhead("ÿc1Teleport off.");
break;
case "tele on":
case me.name + " tele on":
Pather.teleport = true;
me.overhead("ÿc2Teleport on.");
break;
case "a":
case me.name + " a":
if (attack) {
attack = false;
me.overhead("ÿc1Attack off.");
} else {
attack = true;
me.overhead("ÿc2Attack on.");
}
break;
case "flash":
Packet.flash(me.gid);
break;
case "aoff":
case me.name + " aoff":
attack = false;
me.overhead("ÿc1Attack off.");
break;
case "aon":
case me.name + " aon":
attack = true;
me.overhead("ÿc2Attack on.");
break;
case "quit":
case me.name + " quit":
me.overhead("ÿc1quit game ...");
if (logCharOnExit) {
MuleLogger.logChar(); // log the char
}
delay(rand(Config.QuitListDelay[0] * 1e3, Config.QuitListDelay[1] * 1e3));
quit();
break;
case "s": // go to stash and stop
case me.name + " s":
if (!me.inTown) {
Town.goToTown();
}
if (stop) {
stop = false;
me.overhead("ÿc2Resuming.");
} else {
Town.move("stash");
stop = true;
me.overhead("ÿc1Stopping.");
delay(500);
}
break;
case "r":
if (me.playertype != 1 && me.mode === 17) {
me.revive();
}
break;
case "reload":
showConsole();
print("reload");
say("you must type manually the reload command in d2 follower console");
//hideConsole();
break;
case "ancs": // prepare ancients quest a5q5, overwrite the config settings
case me.name + " ancs":
Config.MercWatch = false;
Config.TownCheck = false;
Config.TownHP = 0;
Config.LifeChicken = 0;
Config.ManaChicken = 0;
Config.HealStatus = false;
Config.HPBuffer = 3;
Config.MPBuffer = 3;
Config.RejuvBuffer = 5;
if (me.inTown) {
Town.doChores(true);
me.overhead("ÿc2Prepared with potions for ancients");
}
print("ÿc2Prepared with settings for ancients");
break;
case "ancsoff": // revert to char config from ancients config
Config.MercWatch = true;
Config.TownCheck = true;
Config.TownHP = 30;
Config.HPBuffer = 0;
Config.MPBuffer = 0;
Config.RejuvBuffer = 5;
me.overhead("ÿc1Configuration settings reverted");
break;
case "ai": // anti-idle
case me.name + " ai":
tick = getTickCount() + rand(150e4, 175e4); // trigger anti-idle every ~30 minutes
if (!me.inTown) {
Town.goToTown();
}
if (ai) {
ai = false;
Config.AutoMap = false;
me.overhead("ÿc1anti-idle off");
} else {
ai = true;
me.overhead("ÿc2anti-idle on");
while (ai) {
delay(1000);
if (!ai) {
break;
}
if ((getTickCount() - tick) > 0) {
sendPacket(1, 0x40); // quest status refresh, working as anti-idle
tick += rand(150e4, 175e4);
}
}
}
break;
case "map": // load the mh in the follower d2 window
case me.name + " map":
if (map) {
map = false;
Config.AutoMap = false;
me.overhead("ÿc1Hide the mh ÿc0-> type .reload");
print("ÿc1for hiding the mh, you should manually type ÿc0.reload ÿc4in the chat.");
} else {
map = true;
load("tools/mapthread.js");
Config.AutoMap = true;
me.overhead("ÿc2Show the map");
}
break;
case "end": // stop follower profiles after a random delay
case me.name + " end":
me.overhead("ÿc1game ended. ÿc0leaving ...");
if (logCharOnExit) {
MuleLogger.logChar(); // log the char
}
delay(rand(Config.QuitListDelay[0] * 1e3, Config.QuitListDelay[1] * 1e3));
D2Bot.printToConsole(me.profile + " - end run " + me.gamename);
D2Bot.stop(me.profile, true);
break;
case "restart": // restart the follower profiles after a random delay
case me.name + " restart":
me.overhead("ÿc1rejoin game...");
delay(rand(Config.QuitListDelay[0] * 1e3, Config.QuitListDelay[1] * 1e3));
D2Bot.printToConsole(me.profile + " restart " + me.gamename);
D2Bot.restart();
break;
default:
if (me.classid === 3 && msg.indexOf("aura ") > -1) {
piece = msg.split(" ")[0];
if (piece === me.name || piece === "all") {
skill = parseInt(msg.split(" ")[2], 10);
if (me.getSkill(skill, 1)) {
me.overhead("ÿc3Active aura is: " + skill);
Config.AttackSkill[2] = skill;
Config.AttackSkill[4] = skill;
Skill.setSkill(skill, 0);
//Attack.init();
} else {
me.overhead("ÿc1I don't have that aura.");
}
}
break;
}
if (msg.indexOf("skill ") > -1) {
piece = msg.split(" ")[0];
if (charClass.indexOf(piece) > -1 || piece === me.name || piece === "all") {
skill = parseInt(msg.split(" ")[2], 10);
if (me.getSkill(skill, 1)) {
me.overhead("Attack skill is: " + skill);
Config.AttackSkill[1] = skill;
Config.AttackSkill[3] = skill;
//Attack.init();
} else {
me.overhead("ÿc1I don't have that skill.");
}
}
break;
}
action = msg;
break;
}
}
if (msg && msg.split(" ")[0] === "leader" && commanders.indexOf(nick) > -1) {
piece = msg.split(" ")[1];
if (typeof piece === "string") {
if (commanders.indexOf(piece) === -1) {
commanders.push(piece);
}
me.overhead("ÿc4Switching leader to " + piece);
Config.Leader = piece;
leader = Misc.findPlayer(Config.Leader);
leaderUnit = Misc.getPlayerUnit(Config.Leader);
}
}
};
// Start
addEventListener("chatmsg", this.chatEvent);
for (i = 0; i < 120; i += 1) {
leader = Misc.findPlayer(Config.Leader);
if (leader) {
break;
}
delay(1000);
}
if (!leader) {
print("ÿc1Leader not found - " + me.gamename);
delay(2e5, 3e5);
if (logCharOnExit) {
MuleLogger.logChar(); // log the char
}
delay(rand(Config.QuitListDelay[0] * 1e3, Config.QuitListDelay[1] * 1e3));
quit();
} else if (leader) {
me.overhead("ÿc2Leader found.");
}
while (!Misc.inMyParty(Config.Leader)) {
delay(500);
}
me.overhead("ÿc2Partied.");
delay(500);
// Main Loop
while (Misc.inMyParty(Config.Leader)) {
leaderUnit = Misc.getPlayerUnit(Config.Leader);
if (me.mode === 17) {
if (me.playertype != 1) {
while (!me.inTown) {
me.revive();
delay(1000);
}
Town.move("portalspot");
print("ÿc2Revived!");
} else if (me.playertype == 1) { // stop the HC screen to allow the loot of dead player corpse
Config.MercWatch = false;
Config.TownCheck = false;
Config.HealStatus = false;
Config.TownHP = 0;
Config.LifeChicken = 0;
Config.ManaChicken = 0;
Config.MercChicken = 0;
Config.TownCheck = false;
while(true) {
action = "";
delay(6e5);
}
}
}
while (stop) {
if (!me.inTown) {
Town.goToTown();
Town.move("stash");
}
delay(500);
}
if (!me.inTown) {
field = true;
if (!leaderUnit || !copyUnit(leaderUnit).x) {
leaderUnit = Misc.getPlayerUnit(Config.Leader);
if (leaderUnit) {
me.overhead("ÿc2Leader unit found.");
}
}
this.getCloser();
if (me.classid === 4 && me.getSkill(155, 0) && ((getTickCount() - BCTick >= BCDuration - 30000) || !me.getState(51))) {
this.precast;
}
if (attack) {
Attack.clear(15, false, false, false, true);
this.pickPotions(15);
}
Pickit.pickItems();
if (openContainers) {
this.openContainers(15);
}
if (leader.area !== me.area) {
while (leader.area === 0) {
delay(100);
}
result = this.checkExit(leader, leader.area);
switch (result) {
case 1:
if (Math.abs(leader.area - me.area) === 1 || this.nextArea(me.area).indexOf(leader.area) > -1) {
me.overhead("Taking exit.");
delay(500);
Pather.moveToExit(leader.area, true);
}
break;
case 2:
me.overhead("Taking portal.");
break;
case 3:
me.overhead("ÿc8Taking waypoint.");
delay(500);
Pather.useWaypoint(leader.area, true);
break;
case 4:
me.overhead("Special transit.");
break;
}
while (me.area === 0) {
delay(100);
}
if (!me.inTown && (leader.inTown || Misc.getPlayerAct(Config.Leader) !== me.act)) {
if (!Pather.usePortal(null, leader.name)) {
me.overhead("ÿc1Failed to use leader portal.");
Town.goToTown();
delay(200);
}
}
}
}
if (me.inTown) {
if (!leader.inTown && Misc.getPlayerAct(Config.Leader) === me.act) {
me.overhead("ÿc2Ready");
Town.move("portalspot");
Attack.weaponSwitch(0);
while (!Pather.usePortal(leader.area, leader.name) && leader.area !== me.area) {
me.overhead("ÿc1Failed to use leader portal.");
if (Misc.getPlayerAct(Config.Leader) !== me.act) {
break;
}
}
if (!me.inTown) {
me.overhead("ÿc2Precast");
delay(rand(100, 200));
this.precast;
if (me.classid === 4) {
Attack.clear(10, false, false, false, true);
delay(3e3);
this.precast;
}
while (!Misc.getPlayerUnit(Config.Leader) && !me.dead && !action) {
Attack.clear(10, false, false, false, true);
delay(200);
if (leader.area !== me.area) {
break;
}
}
}
}
if (Misc.getPlayerAct(Config.Leader) !== me.act) {
me.overhead("ÿc8Going to leader's town.");
Town.goToTown(Misc.getPlayerAct(Config.Leader));
delay(200);
Town.move("portalspot");
}
if (field && autoTownChores && leader.inTown && !action) {
me.overhead("ÿc4Running town chores");
Town.doChores();
field = false;
Town.move("portalspot");
}
}
switch (action) {
case "cow":
if (me.area === 1) {
Town.move("portalspot");
if (!Pather.usePortal(39)) {
me.overhead("ÿc1Failed to use cow portal.");
}
}
break;
case me.name + " cowopen":
include("bots/cowopen.js");
CowOpen();
break;
case "move":
case "m":
case me.name + " m":
coord = CollMap.getRandCoordinate(me.x, -1, 1, me.y, -1, 1, 5);
Pather.moveTo(coord.x, coord.y);
break;
case "wp":
case me.name + " wp":
if (me.inTown && !leader.inTown) {
me.overhead("ÿc8Taking waypoint to leader");
Town.move("waypoint");
Pather.useWaypoint(leader.area, true);
break;
}
delay(rand(1, 3) * 500);
unit = getUnit(2, "waypoint");
if (unit) {
WPLoop:
for (i = 0; i < 3; i += 1) {
if (getDistance(me, unit) > 3) {
Pather.moveToUnit(unit);
}
unit.interact();
for (j = 0; j < 100; j += 1) {
if (j % 20 === 0) {
me.cancel();
delay(300);
unit.interact();
}
if (getUIFlag(0x14)) {
break WPLoop;
}
delay(10);
}
}
}
if (getUIFlag(0x14)) {
me.overhead("ÿc2Got wp.");
} else {
me.overhead("ÿc1Failed to get wp.");
}
me.cancel();
break;
case "c":
case me.name + " c":
if (me.playertype != 1 && !me.inTown) {
Town.getCorpse();
}
break;
case "p":
case me.name + " p":
me.overhead("ÿc4!Picking items.");
Pickit.pickItems();
this.pickPotions(20);
if (openContainers) {
this.openContainers(20);
}
me.overhead("ÿc2!Done picking.");
break;
case "1":
if (me.inTown && leader.inTown && Misc.getPlayerAct(Config.Leader) !== me.act) {
me.overhead("ÿc8Going to leader's town.");
Town.goToTown(Misc.getPlayerAct(Config.Leader));
Town.move("portalspot");
} else if (me.inTown) {
say("Going outside.");
Town.goToTown(Misc.getPlayerAct(Config.Leader));
Town.move("portalspot");
if (!Pather.usePortal(leader.area, leader.name)) {
break;
}
while (!Misc.getPlayerUnit(Config.Leader) && !me.dead) {
Attack.clear(10);
delay(200);
}
}
break;
case "2":
if (!me.inTown) {
delay(150);
me.overhead("ÿc4Going to town.");
Pather.usePortal(null, leader.name);
}
break;
case "3":
case me.name + " 3":
if (me.inTown) {
me.overhead("ÿc4Running town chores");
Town.doChores(true);
Town.move("portalspot");
me.overhead("ÿc2Ready");
}
break;
case "gamble":
case me.name + " gamble":
if (me.inTown) {
me.overhead("ÿc4Start gambling");
gold = Config.GambleGoldStart;
Config.GambleGoldStart = me.gold;
Town.gamble();
Config.GambleGoldStart = gold;
Town.move("portalspot");
me.overhead("ÿc2Ready");
}
break;
case "h":
if (me.classid === 4) {
Skill.cast(130);
}
break;
case "bo":
if (me.classid === 4) {
me.overhead("ÿc2BO");
this.precast;
}
break;
case "b": // buff all followers
me.overhead("ÿc2refresh buff");
delay(rand(100, 200));
this.precast;
break;
case "a2":
case "a3":
case "a4":
case "a5":
this.changeAct(parseInt(action[1], 10));
break;
case "tp":
case me.name + " tp":
unit = me.findItem("tbk", 0, 3);
if (unit && unit.getStat(70)) {
unit.interact();
break;
}
unit = me.findItem("tsc", 0, 3);
if (unit) {
unit.interact();
break;
}
me.overhead("ÿc1No TP scrolls or tomes.");
break;
case me.name + " countess":
Town.doChores();
Pather.useWaypoint(6);
this.precast;
if (!Pather.moveToExit([20, 21, 22, 23, 24, 25], true)) {
throw new Error("Failed to move to Countess");
}
Pather.makePortal(true);
break;
case me.name + " andariel":
Town.doChores();
Pather.useWaypoint(35);
this.precast;
if (!Pather.moveToExit([36, 37], true)) {
throw new Error("Failed to move to Catacombs Level 4");
}
Pather.makePortal(true);
break;
case me.name + " summoner":
Town.doChores();
Pather.useWaypoint(74);
this.precast;
if (!Pather.moveToPreset(me.area, 2, 357, -3, -3)) {
throw new Error("Failed to move to Summoner");
}
Pather.makePortal(true);
break;
case me.name + " duriel":
Town.doChores();
Pather.useWaypoint(46);
this.precast;
if (!Pather.moveToExit(getRoom().correcttomb, true)) {
throw new Error("Failed to move to Tal Rasha's Tomb");
}
if (!Pather.moveToPreset(me.area, 2, 152, -11, 3)) {
throw new Error("Failed to move to Orifice");
}
Pather.makePortal(true);
break;
case me.name + " mephisto":
Town.doChores();
Pather.useWaypoint(101);
this.precast;
if (!Pather.moveToExit(102, true)) {
throw new Error("Failed to move to Durance Level 3");
}
Pather.makePortal(true);
break;
case me.name + " chaos":
Town.doChores();
Pather.useWaypoint(107);
this.precast;
if (!Pather.moveToExit(108, true)) {
throw new Error("Failed to move to Chaos Sanctuary");
}
Pather.makePortal(true);
break;
case me.name + " nihlathak":
Town.doChores();
Pather.useWaypoint(123);
this.precast;
if (!Pather.moveToExit(124, true)) {
throw new Error("Failed to go to Nihlathak");
}
Pather.makePortal(true);
break;
case me.name + " throne":
Town.doChores();
Pather.useWaypoint(129);
this.precast;
if (!Pather.moveToExit([130, 131], true)) {
throw new Error("Failed to move to Throne of Destruction.");
}
Pather.makePortal(true);
break;
}
if (action && action.split(" ")[0] === "area:") { // leader should set a key in ToolsThread.js, like case 111: say("area: " + me.area + " x: " + me.x + " y: " + me.y);
var la = parseInt(action.split(" ")[1], 10),
lx = parseInt(action.split(" ")[3], 10),
ly = parseInt(action.split(" ")[5], 10);
if (me.area === la) {
me.overhead("ÿc8moving to leader, area: ÿc0" + la + "ÿc8 x: ÿc0" + lx + "ÿc8 y: ÿc0" + ly);
Pather.moveTo(lx, ly, 3, true);
} else {
if (me.inTown) {
say("ÿc1I'm in town ÿc0- " + me.area);
} else {
say("ÿc1different area, ÿc0cannot get leader position");
}
action = "";
}
}
if (action && action.split(":")[0] === "dist") { // used in getCloser function
dist = (parseInt(action.split(":")[1], 10) > 6 && parseInt(action.split(":")[1], 10) <= 30) ? parseInt(action.split(":")[1], 10) : 6;
me.overhead("ÿc4distance to leader ÿc0= " + dist);
}
if (action.indexOf("talk") > -1) {
this.talk(action.split(" ")[1]);
}
// Communication between 2 teams, 2nd leader is set as follower for the 1st. the commands will be repetead by the 2nd leader
if (action && action.split(" ")[0] === "say" && action.length > 4) {
if (action.split(" ")[1] === "area") {
say("area: " + me.area + " x: " + me.x + " y: " + me.y);
} else if (action.split(" ")[2]) {
say(action.split(" ")[1] + " " + action.split(" ")[2]);
} else {
say(action.split(" ")[1]);
}
}
action = "";
delay(100);
}
return true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment