diff --git a/D2Bot.exe b/D2Bot.exe index 8732cd84e..48c415805 100644 Binary files a/D2Bot.exe and b/D2Bot.exe differ diff --git a/D2Bot.pdb b/D2Bot.pdb index 8e4cf3751..9fdc677e1 100644 Binary files a/D2Bot.pdb and b/D2Bot.pdb differ diff --git a/Meebey.SmartIrc4net.dll b/Meebey.SmartIrc4net.dll deleted file mode 100644 index 6e389be55..000000000 Binary files a/Meebey.SmartIrc4net.dll and /dev/null differ diff --git a/Newtonsoft.Json.dll b/Newtonsoft.Json.dll deleted file mode 100644 index 81639f9b1..000000000 Binary files a/Newtonsoft.Json.dll and /dev/null differ diff --git a/ObjectListView.dll b/ObjectListView.dll deleted file mode 100644 index 162745343..000000000 Binary files a/ObjectListView.dll and /dev/null differ diff --git a/ObjectListView.pdb b/ObjectListView.pdb deleted file mode 100644 index e7005ec8b..000000000 Binary files a/ObjectListView.pdb and /dev/null differ diff --git a/Readme.txt b/Readme.txt index 25f5944d9..01422bdde 100644 --- a/Readme.txt +++ b/Readme.txt @@ -1,4 +1,6 @@ -This is the MASTER (also known as TRUNK) branch. +This is the CORE15 branch. +It will contain most recent D2BS 1.5 core changes. +The rest will be the same as in MASTER branch. The package contains 3 distinct components: D2BS - core diff --git a/d2bs/D2BS.dll b/d2bs/D2BS.dll index 338260d98..c5ecb9e9d 100644 Binary files a/d2bs/D2BS.dll and b/d2bs/D2BS.dll differ diff --git a/d2bs/D2BS.pdb b/d2bs/D2BS.pdb index 957ce47ea..7e61d09a9 100644 Binary files a/d2bs/D2BS.pdb and b/d2bs/D2BS.pdb differ diff --git a/d2bs/D2M.dll b/d2bs/D2M.dll index 14bb33a12..6518b6807 100644 Binary files a/d2bs/D2M.dll and b/d2bs/D2M.dll differ diff --git a/d2bs/js32.dll b/d2bs/js32.dll deleted file mode 100644 index 0b27ea4ce..000000000 Binary files a/d2bs/js32.dll and /dev/null differ diff --git a/d2bs/kolbot/D2BotChannel.dbj b/d2bs/kolbot/D2BotChannel.dbj index 0ff576c62..8fc575a42 100644 --- a/d2bs/kolbot/D2BotChannel.dbj +++ b/d2bs/kolbot/D2BotChannel.dbj @@ -67,8 +67,8 @@ var gameStart, handle, ingame, firstLogin, useChat, channelTick = getTickCount(), lastGameStatus = "ready", fListTick = 0, - loginFail = 0, retry = 0, + badGames = [], joinInfo = { gameName: "", gamePass: "", @@ -177,7 +177,9 @@ function ScriptMsgEvent(msg) { break; case "getMuleMode": - if (AutoMule.torchCheck) { + if (AutoMule.torchAnniCheck === 2) { + scriptBroadcast("2"); + } else if (AutoMule.torchAnniCheck === 1) { scriptBroadcast("1"); } else if (AutoMule.check) { scriptBroadcast("0"); @@ -226,11 +228,19 @@ function main() { delay(500); } - if (gameInfo.error === "@error") { - timeoutDelay("Crash Delay", StarterConfig.CrashDelay * 1e3); + if (gameInfo.error) { + if (!!DataFile.getStats().debugInfo) { + gameInfo.crashInfo = DataFile.getStats().debugInfo; + + D2Bot.printToConsole("Crash Info: Script: " + JSON.parse(gameInfo.crashInfo).currScript + " Area: " + JSON.parse(gameInfo.crashInfo).area, 10); + } + + ControlAction.timeoutDelay("Crash Delay", StarterConfig.CrashDelay * 1e3); D2Bot.updateRuns(); } + DataFile.updateStats("debugInfo", JSON.stringify({currScript: "none", area: "out of game"})); + while (true) { while (me.ingame) { // returns true before actually in game so we can't only use this check if (me.gameReady) { // returns false when switching acts so we can't use while @@ -238,8 +248,9 @@ function main() { if (!ingame) { print("Updating Status"); - D2Bot.updateStatus("Game: " + me.gamename); + //D2Bot.updateStatus("Game: " + me.gamename); + badGames.push(joinInfo.gameName); joinInfo.oldGame = me.gamename; lastGameStatus = "ingame"; ingame = true; @@ -248,6 +259,7 @@ function main() { DataFile.updateStats("runs", gameCount); } + D2Bot.updateStatus("Game: " + me.gamename + timer(gameStart)); } delay(1000); @@ -270,7 +282,9 @@ MainSwitch: case 1: // Lobby D2Bot.updateStatus("Lobby"); - loginFail = 0; + if (!firstLogin) { + firstLogin = true; + } ControlAction.click(6, 27, 480, 120, 20); @@ -359,6 +373,28 @@ MainSwitch: switch (lastGameStatus) { case "pending": // Most likely FTJ (can't detect it directly) + string = ""; + text = ControlAction.getText(4, 438, 300, 326, 150); + + if (text) { + for (i = 0; i < text.length; i += 1) { + string += text[i]; + + if (i !== text.length - 1) { + string += " "; + } + } + + // Didn't meet level restriction + if (string === getLocaleString(5162)) { + print(string); + + retry = 3; + + break; + } + } + retry += 1; D2Bot.updateRuns(); @@ -382,7 +418,8 @@ MainSwitch: if (retry >= 3) { //print("reset game"); - D2Bot.printToConsole("Failed to join 3 times. Aborting."); + D2Bot.printToConsole("Failed to join " + joinInfo.gameName + ". Aborting."); + badGames.push(joinInfo.gameName); lastGameStatus = "ready"; joinInfo.oldGame = joinInfo.gameName; @@ -407,7 +444,7 @@ MainLoop: joinInfo.gameName = joinInfo.gameName[joinInfo.gameName.length - 1].toString().replace(/^\W*/, ""); // use last match and trim it joinInfo.gamePass = StarterConfig.Passwords[n] || ""; - if (joinInfo.gameName !== joinInfo.oldGame) { + if (joinInfo.gameName && joinInfo.gameName !== joinInfo.oldGame && badGames.indexOf(joinInfo.gameName) === -1) { ControlAction.click(6, 652, 469, 120, 20); break MainLoop; @@ -419,14 +456,16 @@ MainLoop: case 4: // Create Game break; case 5: // Join Game - if (joinInfo.oldGame === joinInfo.gameName) { + if (joinInfo.oldGame === joinInfo.gameName || badGames.indexOf(joinInfo.gameName) > -1) { ControlAction.click(6, 433, 433, 96, 32); } D2Bot.updateStatus("Join Game"); if (joinInfo.gameName !== "") { - print("�c2Joining �c0" + joinInfo.gameName); + print("ÿc2Joining ÿc0" + joinInfo.gameName); + ControlAction.setText(1, 606, 148, 155, 20, joinInfo.gamePass); + ControlAction.setText(1, 432, 148, 155, 20, joinInfo.gameName); if (typeof AdvancedConfig[me.profile] === "object" && typeof AdvancedConfig[me.profile].AnnounceGame === "boolean" && typeof AdvancedConfig[me.profile].AnnounceMessage === "string") { sayMsg(AdvancedConfig[me.profile].AnnounceMessage + " " + joinInfo.gameName); @@ -442,11 +481,7 @@ MainLoop: me.blockmouse = true; - try { - joinGame(joinInfo.gameName, joinInfo.gamePass); - } catch (joinErr) { - - } + ControlAction.click(6, 594, 433, 172, 32); me.blockmouse = false; lastGameStatus = "pending"; @@ -474,10 +509,6 @@ MainLoop: ControlAction.click(6, 33, 572, 128, 35); } - if (!firstLogin) { - firstLogin = true; - } - D2Bot.updateStatus("Logging In"); try { @@ -507,26 +538,44 @@ MainLoop: break; case getLocaleString(5208): - loginFail += 1; + D2Bot.updateStatus("Invalid Account"); + D2Bot.printToConsole("Invalid Account"); - if (loginFail < 2) { - timeoutDelay("Login retry", 3000); - ControlAction.click(6, 335, 412, 128, 35); + break; + case getLocaleString(5202): // cd key intended for another product + case getLocaleString(10915): // lod key intended for another product + D2Bot.updateStatus("Invalid CDKey"); + D2Bot.printToConsole("Invalid CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); - break MainSwitch; + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); } - D2Bot.updateStatus("Invalid Account"); - D2Bot.printToConsole("Invalid Account"); - break; case getLocaleString(5199): D2Bot.updateStatus("Disabled CDKey"); - D2Bot.printToConsole("Disabled CDKey"); + D2Bot.printToConsole("Disabled CDKey: " + gameInfo.mpq, 6); D2Bot.CDKeyDisabled(); if (gameInfo.switchKeys) { - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + + break; + case getLocaleString(10913): + D2Bot.updateStatus("Disabled LoD CDKey"); + D2Bot.printToConsole("Disabled LoD CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); } else { D2Bot.stop(); @@ -543,6 +592,13 @@ MainLoop: D2Bot.updateStatus("Login Error"); D2Bot.printToConsole("Login Error - " + string); + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + break; } } @@ -605,15 +661,15 @@ MainLoop: ControlAction.click(6, 351, 337, 96, 32); break; case 19: // Login - Cdkey In Use - D2Bot.printToConsole("CD-Key in use by " + ControlAction.getText(4, 158, 310, 485, 40)); + D2Bot.printToConsole(gameInfo.mpq + " is in use by " + ControlAction.getText(4, 158, 310, 485, 40), 6); D2Bot.CDKeyInUse(); if (gameInfo.switchKeys) { - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); } else { - timeoutDelay("CD-Key in use", StarterConfig.CDKeyInUseDelay * 6e4); ControlAction.click(6, 335, 450, 128, 35); + ControlAction.timeoutDelay("CD-Key in use", StarterConfig.CDKeyInUseDelay * 6e4); } break; @@ -641,26 +697,26 @@ MainLoop: switch (string) { case getLocaleString(10914): - D2Bot.printToConsole("LoD key in use by " + ControlAction.getText(4, 158, 310, 485, 40)); + D2Bot.printToConsole(gameInfo.mpq + " LoD key in use by " + ControlAction.getText(4, 158, 310, 485, 40), 6); D2Bot.CDKeyInUse(); if (gameInfo.switchKeys) { - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); } else { ControlAction.click(6, 335, 450, 128, 35); - timeoutDelay("LoD key in use", StarterConfig.CDKeyInUseDelay * 6e4); + ControlAction.timeoutDelay("LoD key in use", StarterConfig.CDKeyInUseDelay * 6e4); } break; default: if (gameInfo.switchKeys) { D2Bot.printToConsole("Invalid CD-Key"); - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); } else { ControlAction.click(6, 335, 450, 128, 35); - timeoutDelay("Invalid CD-Key", StarterConfig.CDKeyInUseDelay * 6e4); + ControlAction.timeoutDelay("Invalid CD-Key", StarterConfig.CDKeyInUseDelay * 6e4); } break; @@ -669,13 +725,38 @@ MainLoop: break; case 23: // Character Select - Connecting case 42: // Empty character screen + string = ""; + text = ControlAction.getText(4, 45, 318, 531, 140); + + if (text) { + for (i = 0; i < text.length; i += 1) { + string += text[i]; + + if (i !== text.length - 1) { + string += " "; + } + } + + if (string === getLocaleString(11161)) { // CDKey disabled from realm play + D2Bot.updateStatus("Realm Disabled CDKey"); + D2Bot.printToConsole("Realm Disabled CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + } + } + if (!locationTimeout(StarterConfig.ConnectingTimeout * 1e3, location)) { - //print("QQQ"); ControlAction.click(6, 33, 572, 128, 35); - } - if (gameInfo.rdBlocker) { - D2Bot.restart(); + if (gameInfo.rdBlocker) { + D2Bot.restart(); + } } break; @@ -703,7 +784,7 @@ MainLoop: break; case 38: // Game is full - //D2Bot.printToConsole("Game is full"); + badGames.push(joinInfo.gameName); ControlAction.click(6, 652, 469, 120, 20); ControlAction.click(6, 433, 433, 96, 32); @@ -719,4 +800,4 @@ MainLoop: break; } -} +} \ No newline at end of file diff --git a/d2bs/kolbot/D2BotChannelMaster.dbj b/d2bs/kolbot/D2BotChannelMaster.dbj deleted file mode 100644 index 7f854efce..000000000 --- a/d2bs/kolbot/D2BotChannelMaster.dbj +++ /dev/null @@ -1,875 +0,0 @@ -/** -* This was initially made by me for use with my Rusher channel. It makes it possible to sit in a channel without timing out, and allow others (or yourself) to load profiles at will. -* This will pass the game information to both the person requesting the game, and the runners/helpers defined. Whatever game name/password you set in your 'master' profile, will be the game name used. -* Currently, this is setup to stop the client after it leaves the game. It will not sit in channel. It will also only try to join the game once. If it fails, it will stop and the person will have to request again. -* -* @Author Adhd -* @LastUpdate 12/17/13 14:38 Alaskan Time -* @Filename D2BotChannelMaster.dbj -* -*/ - -var StarterConfig = { - - //This is the CHANNEL MASTER. It starts all profiles below. - ChannelMasterProfile : "master", // Master of the channel. starts other profiles. **SET game name and password in this profile. - whisper: true, // Whisper the game name and pass to the user instead of saying it in chat globally. - currentGames: false, // Give the info of all Characters for the trigger word requested in chat, If none are available. - gameMessage: "Please make the following game, and someone will join you: ", // Message to say when a trigger word is found. the game name and password will be added after this phrase. - unavailableMessage: "I am sorry, None of those rushers are available at the moment.", // Message to say when no characters are available for that trigger word - - - // ChannelConfig can override these options for individual profiles. - JoinChannel : "Op mr.crush", // Default channel. Can be an array of channels - ["channel 1", "channel 2"] - FirstJoinMessage : "", // Default join message. Can be an array of messages - - //Global script settings - JoinGameDelay : 9, // Seconds to wait before joining a new game - ChatActionsDelay : 2, // Seconds to wait in lobby before entering a channel - SwitchKeyDelay : 5, // Seconds to wait before switching a used/banned key or after realm down - CrashDelay : 5, // Seconds to wait after a d2 window crash - RealmDownDelay : 3, // Minutes to wait after getting Realm Down message - UnableToConnectDelay : 5, // Minutes to wait after Unable To Connect message - CDKeyInUseDelay : 5, // Minutes to wait before connecting again if CD-Key is in use. - ConnectingTimeout : 20, // Seconds to wait before cancelling the 'Connecting...' screen - PleaseWaitTimeout : 10, // Seconds to wait before cancelling the 'Please Wait...' screen - WaitInLineTimeout : 60, // Seconds to wait before cancelling the 'Waiting in Line...' screen - - -}; - -var ChannelConfig = { - - /* Format is as follows: - * - * //Trigger word to look for - * "!startMyProfile": { - * - * "Profile 1 to start": { - * joinChannel: "", //Can be an array - ["op chan", "op chan2"], - * FirstJoinMessage: "", //Can be an array - * otherProfiles: ["Barb", "Pally"] //Must be an array - * }, - * "Profile 2 to start": { - * joinChannel: "", - * FirstJoinMessage: "", - * otherProfiles: ["helper Barb"] - * } - * }, - - * "!startMyOtherProfile": { - * - * "Profile 1 to start": { - * joinChannel: "", - * FirstJoinMessage: "", - * otherProfiles: ["Barb", "Pally"] - * }, - * "Profile 2 to start": { - * joinChannel: "", - * FirstJoinMessage: "", - * otherProfiles: ["helper Barb"] - * } - * }; - */ -}; - -// Do not edit below here. - -include("json2.js"); -include("OOG.js"); -include("gambling.js"); -include("torchsystem.js"); -include("common/misc.js"); - -if (!FileTools.exists("data/" + me.profile + ".json")) { - DataFile.create(); -} -if (!FileTools.exists("/rushers")) { - var dir = dopen("/"); - dir.create("rushers"); -} - -var gameInfo, gameStart, inGame, chatActionsDone, pingQuit, date, handle, -useChat, firstLogin, connectFail, CharInfo, GameStuff, currentRusher, lines, -gameCount = DataFile.getStats().runs + 1, -myConfig = getConfig(), -lastGameStatus = "ready", -oldIndex = 0, -loginFail = 0, -chanInfo = { - joinChannel : "", - firstMsg : "" -}, -RushData = { - create: function (rusher) { - var obj, string; - - obj = { - status: "closed", - gameName: "", - gamePass: "" - }; - - string = JSON.stringify(obj); - FileTools.writeText('rushers/' + rusher + ".json", string); - }, - - read: function (rusher) { - var obj, string; - - string = FileTools.readText('rushers/' + rusher + ".json"); - obj = JSON.parse(string); - - return obj; - }, - - write: function (obj, rusher) { - var string; - - string = JSON.stringify(obj); - - FileTools.writeText('rushers/' + rusher + ".json", string); - } -}; - -function getConfig() { - - for (var i in ChannelConfig) { - if (typeof ChannelConfig[i] == "object") { - - for (var profile in ChannelConfig[i]) { - if (profile == me.profile) { - print("ÿc9Using a custom Runner profile"); - return ChannelConfig[i][profile]; - } - - if (typeof ChannelConfig[i][profile].otherProfiles == "object") { - for (var y = 0; y < ChannelConfig[i][profile].otherProfiles.length; y += 1) { - if (ChannelConfig[i][profile].otherProfiles[y] === me.profile) { - print("ÿc7Using a custom Helper profile"); - return profile; - } - } - } - } - } - } - - if (me.profile === StarterConfig.ChannelMasterProfile) { - print("ÿc8Utilizing the 'Master' profile"); - } else { - print("ÿc1No custom profile found!"); - } - return false; -} - -function sayMsg(string) { - if (!useChat) { - return; - } - - say(string); -} - -function getTime() { - - if (date) { - var h = date.getHours(), - m = date.getMinutes(), - s = date.getSeconds(), - dateString = "[" + (h < 10 ? "0" + h : h) + ":" + (m < 10 ? "0" + m : m) + ":" + (s < 10 ? "0" + s : s) + "]"; - - return dateString; - } else { - - return false; - } -} - -function ReceiveCopyData(mode, msg) { - var obj; - - switch (msg) { - case "Handle": - handle = mode; - - break; - } - - switch (mode) { - case 2: // Game info - print("Received Game Info"); - - gameInfo = JSON.parse(msg); - - break; - case 4: // Heartbeat ping - if (msg === "pingreq") { - sendCopyData(null, me.windowtitle, 4, "pingrep"); - } - - break; - case 5: //request FROM master to send info about me/game - if (msg === "request") { - print("Received request for info from the master"); - sendCopyData(null, StarterConfig.ChannelMasterProfile, 6, JSON.stringify({ - charName : me.charname, - gameName : me.gamename, - diff : me.diff, - timeIn : getTime() - })); - } - break; - case 6: //Read info from rusher - print("Received Info from Rusher"); - CharInfo = JSON.parse(msg); - - break; - case 0xf124: // Cached info retrieval - if (msg !== "null") { - gameInfo.crashInfo = JSON.parse(msg); - } - - break; - } -} - -function locationTimeout(time, location) { - var endtime = getTickCount() + time; - while (getLocation() === location && endtime > getTickCount()) { - delay(500); - } - - return (getLocation() !== location); -} - -function updateCount() { - D2Bot.updateCount(); - delay(1000); - ControlAction.click(6, 264, 366, 272, 35); - - try { - login(me.profile); - } catch (e) {} - - delay(1000); - ControlAction.click(6, 33, 572, 128, 35); -} - -function timer(tick) { - if (!tick) { - return ""; - } - - var min, - sec; - - min = Math.floor((getTickCount() - tick) / 60000).toString(); - - if (min <= 9) { - min = "0" + min; - } - - sec = (Math.floor((getTickCount() - tick) / 1000) % 60).toString(); - - if (sec <= 9) { - sec = "0" + sec; - } - - return " (" + min + ":" + sec + ")"; -} - -function main() { - - debugLog(me.profile); - addEventListener('copydata', ReceiveCopyData); - - while (!handle) { - delay(100); - } - - DataFile.updateStats("handle", handle); - delay(500); - D2Bot.init(); - load("tools/heartbeat.js"); - - while (!gameInfo) { - D2Bot.requestGameInfo(); - delay(500); - } - - if (gameInfo.error) { - delay(200); - - if (gameInfo.crashInfo) { - D2Bot.printToConsole("Crash Info: Script: " + gameInfo.crashInfo.currScript + " Area: " + gameInfo.crashInfo.area, 10); - } - - ControlAction.timeoutDelay("Crash Delay", StarterConfig.CrashDelay * 1e3); - D2Bot.updateRuns(); - } - - while (true) { - while (me.ingame) { - if (me.gameReady) { - - if (!inGame) { - date = new Date(); - gameStart = getTickCount(); - - print("Updating Status"); - - lastGameStatus = "stop"; - inGame = true; - - DataFile.updateStats("runs", gameCount); - DataFile.updateStats("ingameTick"); - } - - D2Bot.updateStatus("Game: " + me.gamename + timer(gameStart)); - } - - delay(1000); - } - - locationAction(getLocation()); - delay(1000); - } -} - -function locationAction(location) { - var i, control, string, text; - - MainSwitch : switch (location) { - case 0: - break; - case 1: // Lobby - D2Bot.updateStatus("Lobby"); - - loginFail = 0; - - ControlAction.click(6, 27, 480, 120, 20); - - break; - case 2: // Waiting In Line - D2Bot.updateStatus("Waiting..."); - locationTimeout(StarterConfig.WaitInLineTimeout * 1e3, location); - ControlAction.click(6, 433, 433, 96, 32); - - break; - case 3: // Lobby Chat - D2Bot.updateStatus("Lobby Chat"); - - if (lastGameStatus === "stop" || lastGameStatus === "pending") { - D2Bot.stop(); - } - - if (!chatActionsDone) { - chatActionsDone = true; - - if (myConfig && myConfig.hasOwnProperty("JoinChannel")) { - chanInfo.joinChannel = myConfig.JoinChannel; - } else { - chanInfo.joinChannel = StarterConfig.JoinChannel; - } - - if (myConfig && myConfig.hasOwnProperty("FirstJoinMessage")) { - chanInfo.firstMsg = myConfig.FirstJoinMessage; - } else { - chanInfo.firstMsg = StarterConfig.FirstJoinMessage; - } - - if (chanInfo.joinChannel) { - if (typeof chanInfo.joinChannel === "string") { - chanInfo.joinChannel = [chanInfo.joinChannel]; - } - - if (typeof chanInfo.firstMsg === "string") { - chanInfo.firstMsg = [chanInfo.firstMsg]; - } - - for (i = 0; i < chanInfo.joinChannel.length; i += 1) { - ControlAction.timeoutDelay("Chat delay", StarterConfig.ChatActionsDelay * 1e3); - - if (ControlAction.joinChannel(chanInfo.joinChannel[i])) { - useChat = true; - } else { - print("?c1Unable to join channel, disabling chat messages."); - - useChat = false; - } - - if (chanInfo.firstMsg[i] !== "") { - sayMsg(chanInfo.firstMsg[i]); - delay(500); - } - } - } - } - - // Adhd Channel Master - if (StarterConfig.ChannelMasterProfile === me.profile) { - var i, x, myProfiles, words, getCurrent, foundOne, RusherDiff, helper, y, profile, wordsArray, whisper, msg, - loopstart = getTickCount(); - - D2Bot.updateStatus("Waiting for Trigger"); - - MainLoop : while (true) { - - if (oldIndex >= 100000) { - D2Bot.restart(true); - } - - lines = ControlAction.getText(4, 28, 410, 354, 298); - foundOne = false; - - if (getLocation() === 17) { - break; - } - - if (lines) { - for (; oldIndex < lines.length; oldIndex++) { - words = lines[oldIndex].toLowerCase().replace(/<|>|ÿc4|/g, ""); - wordsArray = words.split(" "); - - for (i in ChannelConfig) { - - if (ChannelConfig.hasOwnProperty(i)) { - i = i.toLowerCase(); - - if (words.match(i)) { - - if (words.match(/champion|slayer|matriarch|sir|dame|lord|lady|baroness|baron|count|countess|duke|duchess|king|queen/g)) { - whisper = wordsArray[1]; - } else { - whisper = wordsArray[0]; - } - - myProfiles = ChannelConfig[i]; - - for (x in myProfiles) { - if (myProfiles.hasOwnProperty(x)) { - - if (!FileTools.exists('rushers/' + x + ".json")) { - RushData.create(x); - } - - if (!sendCopyData(null, x, 4, "pingrep")) { - currentRusher = RushData.read(x); - currentRusher.status = "closed"; - RushData.write(currentRusher, x); - } - - currentRusher = RushData.read(x); - - if (currentRusher.status === "closed") { - - foundOne = true; - gameCount += 1; - D2Bot.updateRuns(); - DataFile.updateStats("runs", gameCount); - - currentRusher.status = "open"; - currentRusher.gameName = gameInfo.gameName + gameCount; - currentRusher.gamePass = gameInfo.gamePass; - RushData.write(currentRusher, x); - - msg = " " + gameInfo.gameName + gameCount + (gameInfo.gamePass === "" ? "" : " // " + gameInfo.gamePass + " "); - - if (StarterConfig.whisper) { - say("/whisper " + whisper + " " + StarterConfig.gameMessage + msg); - } else { - say("/me " + StarterConfig.gameMessage + msg); - } - - D2Bot.start(x); - oldIndex++; - break; - } - } - } - - if (!foundOne) { - say(StarterConfig.unavailableMessage); - - if (StarterConfig.currentGames) { - for (x in myProfiles) { - if (myProfiles.hasOwnProperty(x)) { - sendCopyData(null, x, 5, "request"); - delay(500); - - if (CharInfo) { - if (CharInfo.charName !== undefined) { - - switch (CharInfo.diff) { - case 0: - RusherDiff = "Normal"; - break; - case 1: - RusherDiff = "Nightmare"; - break; - case 2: - RusherDiff = "Hell"; - break; - default: - RusherDiff = "Normal"; - break; - } - - say("/me | Rusher: " + CharInfo.charName + " | Current Game: " + CharInfo.gameName + "| Game Difficulty: " + RusherDiff + " | Joined game at: " + CharInfo.timeIn); - } - } - } - } - } - } - } - } - } - } - } - - if (getTickCount() - loopstart > 180000) { - - ControlAction.click(6, 652, 469, 120, 20); // Click Join - delay(3000); - ControlAction.click(6, 433, 433, 96, 32); // Click Cancel - - loopstart = getTickCount(); - } - delay(200); - } - } - //END Adhd Channel Master - - if (!ControlAction.click(6, 652, 469, 120, 20)) { // Join - break; - } - - if (!locationTimeout(5000, location)) { // in case join button gets bugged - if (!ControlAction.click(6, 533, 469, 120, 20)) { // Create - break; - } - - if (!ControlAction.click(6, 652, 469, 120, 20)) { // Join - break; - } - } - - break; - case 4: // Create Game - break; - case 5: // Join Game - if (!FileTools.exists('rushers/' + me.profile + ".json")) { - GameStuff = RushData.read(myConfig); //For helpers, it returns their leaders profile - } else { - GameStuff = RushData.read(me.profile); - } - - delay(500); - - if (GameStuff && GameStuff.gameName !== "") { - - ControlAction.setText(1, 606, 148, 155, 20, GameStuff.gamePass); - ControlAction.setText(1, 432, 148, 155, 20, GameStuff.gameName); - - if (lastGameStatus === "pending" || (gameInfo.error === "@error" && DataFile.getStats().gameName === GameStuff.gameName)) { - if (gameInfo.error === "@error") { - gameInfo.error = ""; - } - - lastGameStatus = "ready"; - } - - D2Bot.updateRuns(); - - print("ÿc2joining game " + GameStuff.gameName); - - delay(StarterConfig.JoinGameDelay * 1000); - - me.blockMouse = true; - - DataFile.updateStats("gameName", GameStuff.gameName); - ControlAction.click(6, 594, 433, 172, 32); - - me.blockMouse = false; - - lastGameStatus = "pending"; - - locationTimeout(15000, location); - - } - break; - case 6: // Ladder - break; - case 7: // Channel List - break; - case 8: // Main Menu - case 9: // Login - case 12: // Character Select - case 18: // D2 Splash - // Single Player screen fix - if (getLocation() === 12 && !getControl(4, 626, 100, 151, 44)) { - ControlAction.click(6, 33, 572, 128, 35); - - break; - } - - if (firstLogin && getLocation() === 9) { // multiple realm botting fix in case of R/D or disconnect - ControlAction.click(6, 33, 572, 128, 35); - } - - if (!firstLogin) { - firstLogin = true; - } - - D2Bot.updateStatus("Logging In"); - - if (myConfig && myConfig.hasOwnProperty("otherProfiles")) { - for (var y = 0; y < myConfig.otherProfiles.length; y += 1) { - - if (sendCopyData(null, myConfig.otherProfiles[y], 4, "pingrep")) { - print("ÿc4Helper stuck in game, stopping.."); - D2Bot.stop(myConfig.otherProfiles[y]); - } - - D2Bot.start(myConfig.otherProfiles[y]); - print("ÿc3starting " + myConfig.otherProfiles[y]); - delay(500); - } - } - - try { - login(me.profile); - } catch (e) { - print(e + " " + getLocation()); - } - - break; - case 10: // Login Error - string = ""; - text = ControlAction.getText(4, 199, 377, 402, 140); - - if (text) { - for (i = 0; i < text.length; i += 1) { - string += text[i]; - - if (i !== text.length - 1) { - string += " "; - } - } - - switch (string) { - case getLocaleString(5207): - D2Bot.updateStatus("Invalid Password"); - D2Bot.printToConsole("Invalid Password"); - - break; - case getLocaleString(5208): - loginFail += 1; - - if (loginFail < 2) { - ControlAction.timeoutDelay("Login retry", 3000); - ControlAction.click(6, 335, 412, 128, 35); - - break MainSwitch; - } - - D2Bot.updateStatus("Invalid Account"); - D2Bot.printToConsole("Invalid Account"); - - break; - case getLocaleString(5199): - D2Bot.updateStatus("Disabled CDKey"); - D2Bot.printToConsole("Disabled CDKey: " + gameInfo.mpq, 6); - D2Bot.CDKeyDisabled(); - - if (gameInfo.switchKeys) { - ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); - D2Bot.restart(true); - } else { - D2Bot.stop(); - } - - break; - case getLocaleString(5347): - D2Bot.updateStatus("Disconnected"); - D2Bot.printToConsole("Disconnected"); - ControlAction.click(6, 335, 412, 128, 35); - - break MainSwitch; - default: - D2Bot.updateStatus("Login Error"); - D2Bot.printToConsole("Login Error - " + string); - - break; - } - } - - ControlAction.click(6, 335, 412, 128, 35); - while (true) { - delay(1000); - } - - break; - case 11: // Unable To Connect - D2Bot.updateStatus("Unable To Connect"); - - if (connectFail) { - ControlAction.timeoutDelay("Unable to Connect", StarterConfig.UnableToConnectDelay * 6e4); - - connectFail = false; - } - - if (!ControlAction.click(6, 335, 450, 128, 35)) { - break; - } - - connectFail = true; - - break; - case 13: // Realm Down - Character Select screen - D2Bot.updateStatus("Realm Down"); - delay(1000); - - if (!ControlAction.click(6, 33, 572, 128, 35)) { - break; - } - - updateCount(); - ControlAction.timeoutDelay("Realm Down", StarterConfig.RealmDownDelay * 6e4); - D2Bot.CDKeyRD(); - - if (gameInfo.switchKeys && !gameInfo.rdBlocker) { - D2Bot.printToConsole("Realm Down - Changing CD-Key"); - ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); - D2Bot.restart(true); - } else { - D2Bot.printToConsole("Realm Down - Restart"); - D2Bot.restart(); - } - - break; - case 14: // Character Select / Main Menu - Disconnected - D2Bot.updateStatus("Disconnected"); - delay(500); - ControlAction.click(6, 351, 337, 96, 32); - - break; - case 16: // Character Select - Please Wait popup - if (!locationTimeout(StarterConfig.PleaseWaitTimeout * 1e3, location)) { - ControlAction.click(6, 351, 337, 96, 32); - } - - break; - case 17: // Lobby - Lost Connection - just click okay, since we're toast anyway - delay(1000); - ControlAction.click(6, 351, 337, 96, 32); - chatActionsDone = false; - oldIndex = 0; - - break; - case 19: // Login - Cdkey In Use - D2Bot.printToConsole(gameInfo.mpq + " is in use by " + ControlAction.getText(4, 158, 310, 485, 40), 6); - D2Bot.CDKeyInUse(); - - if (gameInfo.switchKeys) { - ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); - D2Bot.restart(true); - } else { - ControlAction.click(6, 335, 450, 128, 35); - ControlAction.timeoutDelay("CD-Key in use", StarterConfig.CDKeyInUseDelay * 6e4); - } - - break; - case 20: // Single Player - Select Difficulty - break; - case 21: // Main Menu - Connecting - if (!locationTimeout(StarterConfig.ConnectingTimeout * 1e3, location)) { - ControlAction.click(6, 330, 416, 128, 35); - } - - break; - case 22: // Login - Invalid Cdkey (classic or xpac) - text = ControlAction.getText(4, 162, 270, 477, 50); - string = ""; - - if (text) { - for (i = 0; i < text.length; i += 1) { - string += text[i]; - - if (i !== text.length - 1) { - string += " "; - } - } - } - - switch (string) { - case getLocaleString(10914): - D2Bot.printToConsole(gameInfo.mpq + " LoD key in use by " + ControlAction.getText(4, 158, 310, 485, 40), 6); - D2Bot.CDKeyInUse(); - - if (gameInfo.switchKeys) { - ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); - D2Bot.restart(true); - } else { - ControlAction.click(6, 335, 450, 128, 35); - ControlAction.timeoutDelay("LoD key in use", StarterConfig.CDKeyInUseDelay * 6e4); - } - - break; - default: - if (gameInfo.switchKeys) { - D2Bot.printToConsole("Invalid CD-Key"); - ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); - D2Bot.restart(true); - } else { - ControlAction.click(6, 335, 450, 128, 35); - ControlAction.timeoutDelay("Invalid CD-Key", StarterConfig.CDKeyInUseDelay * 6e4); - } - - break; - } - - break; - case 23: // Character Select - Connecting - case 42: // Empty character screen - if (!locationTimeout(StarterConfig.ConnectingTimeout * 1e3, location)) { - ControlAction.click(6, 33, 572, 128, 35); - } - - if (gameInfo.rdBlocker) { - D2Bot.restart(); - } - - break; - case 24: // Server Down - not much to do but wait.. - break; - case 25: // Lobby - Please Wait - if (!locationTimeout(StarterConfig.PleaseWaitTimeout * 1e3, location)) { - ControlAction.click(6, 351, 337, 96, 32); - } - - break; - case 26: // Lobby - Game Name Exists - break; - case 27: // Gateway Select - ControlAction.click(6, 436, 538, 96, 32); - - break; - case 28: // Lobby - Game Does Not Exist - lastGameStatus = "stop"; - break; - case 38: // Game is full - break; - default: - if (location !== undefined) { - D2Bot.printToConsole("Unhandled location " + location); - takeScreenshot(); - delay(500); - D2Bot.restart(); - } - - break; - } -} \ No newline at end of file diff --git a/d2bs/kolbot/D2BotFollow.dbj b/d2bs/kolbot/D2BotFollow.dbj index 2be9f82f9..b5ae0015b 100644 --- a/d2bs/kolbot/D2BotFollow.dbj +++ b/d2bs/kolbot/D2BotFollow.dbj @@ -45,6 +45,7 @@ var AdvancedConfig = { */ // Put your lines under this one. Multiple entries are separated by commas. No comma after the last one. + }; @@ -54,16 +55,16 @@ include("json2.js"); include("OOG.js"); include("automule.js"); include("gambling.js"); +include("craftingsystem.js"); include("torchsystem.js"); include("common/misc.js"); var i, j, gameInfo, joinInfo, gameStart, ingame, handle, - connectFail, firstLogin, chatActionsDone, lastGameTick, + firstLogin, chatActionsDone, lastGameTick, connectFail, gameCount = DataFile.getStats().runs + 1, lastGameStatus = "ready", leader = "", - lastGame = [], - loginFail = 0; + lastGame = []; if (!FileTools.exists("data/" + me.profile + ".json")) { DataFile.create(); @@ -107,9 +108,15 @@ function ScriptMsgEvent(msg) { case "torch": TorchSystem.check = true; + break; + case "crafting": + CraftingSystem.check = true; + break; case "getMuleMode": - if (AutoMule.torchCheck) { + if (AutoMule.torchAnniCheck === 2) { + scriptBroadcast("2"); + } else if (AutoMule.torchAnniCheck === 1) { scriptBroadcast("1"); } else if (AutoMule.check) { scriptBroadcast("0"); @@ -144,7 +151,7 @@ function ReceiveCopyData(mode, msg) { break; case 3: // Game request // Don't let others join mule/torch/key/gold drop game - if (AutoMule.inGame || Gambling.inGame || TorchSystem.inGame) { + if (AutoMule.inGame || Gambling.inGame || TorchSystem.inGame || CraftingSystem.inGame) { break; } @@ -188,6 +195,7 @@ function timer(tick) { } function main() { + debugLog(me.profile); addEventListener('copydata', ReceiveCopyData); addEventListener('scriptmsg', ScriptMsgEvent); @@ -204,17 +212,33 @@ function main() { delay(500); } - if (gameInfo.error === "@error") { + if (gameInfo.error) { + //D2Bot.retrieve(); + delay(200); + + if (!!DataFile.getStats().debugInfo) { + gameInfo.crashInfo = DataFile.getStats().debugInfo; + + D2Bot.printToConsole("Crash Info: Script: " + JSON.parse(gameInfo.crashInfo).currScript + " Area: " + JSON.parse(gameInfo.crashInfo).area, 10); + } + + /*if (gameInfo.crashInfo) { + D2Bot.printToConsole("Crash Info: Script: " + gameInfo.crashInfo.currScript + " Area: " + gameInfo.crashInfo.area + (gameInfo.crashInfo.hasOwnProperty("lastAction") ? " " + gameInfo.crashInfo.lastAction : ""), 10); + }*/ + ControlAction.timeoutDelay("Crash Delay", StarterConfig.CrashDelay * 1e3); D2Bot.updateRuns(); } + //D2Bot.store(JSON.stringify({currScript: "none", area: "out of game"})); + DataFile.updateStats("debugInfo", JSON.stringify({currScript: "none", area: "out of game"})); + while (true) { while (me.ingame) { // returns true before actually in game so we can't only use this check if (me.gameReady) { // returns false when switching acts so we can't use while if (!ingame) { - print("Updating Status"); - D2Bot.updateStatus("Game: " + me.gamename); + print("ÿc4Updating Status"); + //D2Bot.updateStatus("Game: " + me.gamename); lastGameStatus = "ingame"; ingame = true; @@ -223,6 +247,7 @@ function main() { DataFile.updateStats("runs", gameCount); } + D2Bot.updateStatus("Game: " + me.gamename + timer(gameStart)); } delay(1000); @@ -264,7 +289,9 @@ MainSwitch: case 1: // Lobby D2Bot.updateStatus("Lobby"); - loginFail = 0; + if (!firstLogin) { + firstLogin = true; + } if (StarterConfig.JoinChannel !== "") { ControlAction.click(6, 27, 480, 120, 20); @@ -273,7 +300,7 @@ MainSwitch: } if (ingame) { - if (AutoMule.outOfGameCheck() || TorchSystem.outOfGameCheck() || Gambling.outOfGameCheck()) { + if (AutoMule.outOfGameCheck() || TorchSystem.outOfGameCheck() || Gambling.outOfGameCheck() || CraftingSystem.outOfGameCheck()) { break; } @@ -311,7 +338,7 @@ MainSwitch: D2Bot.updateStatus("Lobby Chat"); if (ingame) { - if (AutoMule.outOfGameCheck() || TorchSystem.outOfGameCheck() || Gambling.outOfGameCheck()) { + if (AutoMule.outOfGameCheck() || TorchSystem.outOfGameCheck() || Gambling.outOfGameCheck() || CraftingSystem.outOfGameCheck()) { break; } @@ -378,6 +405,8 @@ MainSwitch: JoinLoop2: for (i = 0; i < 5; i += 1) { for (j = 0; j < leader.length; j += 1) { + joinInfo = false; + D2Bot.requestGame(leader[j]); delay(100); @@ -385,11 +414,8 @@ JoinLoop2: ControlAction.setText(1, 606, 148, 155, 20, joinInfo.gamePass); ControlAction.setText(1, 432, 148, 155, 20, joinInfo.gameName); - if (lastGameStatus === "pending" || (gameInfo.error === "@error" && DataFile.getStats().gameName === joinInfo.gameName)) { - if (gameInfo.error === "@error") { - gameInfo.error = ""; - } - + if (lastGameStatus === "pending" || (gameInfo.error && DataFile.getStats().gameName === joinInfo.gameName)) { + D2Bot.printToConsole("Failed to join game"); ControlAction.timeoutDelay("Join Delay", StarterConfig.JoinRetryDelay * 1000, joinCheck, leader[j]); D2Bot.updateRuns(); D2Bot.requestGame(leader[j]); @@ -426,7 +452,7 @@ JoinLoop2: lastGame.push(joinInfo.gameName); - if (lastGame.length > 5) { + if (lastGame.length > leader.length) { // Might need a fixed number. Right now it stores 1 game per leader. lastGame.shift(); } @@ -459,10 +485,6 @@ JoinLoop2: ControlAction.click(6, 33, 572, 128, 35); } - if (!firstLogin) { - firstLogin = true; - } - D2Bot.updateStatus("Logging In"); try { @@ -492,18 +514,23 @@ JoinLoop2: break; case getLocaleString(5208): - loginFail += 1; + D2Bot.updateStatus("Invalid Account"); + D2Bot.printToConsole("Invalid Account"); - if (loginFail < 2) { - ControlAction.timeoutDelay("Login retry", 3000); - ControlAction.click(6, 335, 412, 128, 35); + break; + case getLocaleString(5202): // cd key intended for another product + case getLocaleString(10915): // lod key intended for another product + D2Bot.updateStatus("Invalid CDKey"); + D2Bot.printToConsole("Invalid CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); - break MainSwitch; + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); } - D2Bot.updateStatus("Invalid Account"); - D2Bot.printToConsole("Invalid Account"); - break; case getLocaleString(5199): D2Bot.updateStatus("Disabled CDKey"); @@ -517,6 +544,19 @@ JoinLoop2: D2Bot.stop(); } + break; + case getLocaleString(10913): + D2Bot.updateStatus("Disabled LoD CDKey"); + D2Bot.printToConsole("Disabled LoD CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + break; case getLocaleString(5347): D2Bot.updateStatus("Disconnected"); @@ -528,6 +568,13 @@ JoinLoop2: D2Bot.updateStatus("Login Error"); D2Bot.printToConsole("Login Error - " + string); + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + break; } } @@ -546,14 +593,14 @@ JoinLoop2: ControlAction.timeoutDelay("Unable to Connect", StarterConfig.UnableToConnectDelay * 6e4); connectFail = false; + } else { + connectFail = true; } if (!ControlAction.click(6, 335, 450, 128, 35)) { break; } - connectFail = true; - break; case 13: // Realm Down - Character Select screen D2Bot.updateStatus("Realm Down"); @@ -659,12 +706,38 @@ JoinLoop2: break; case 23: // Character Select - Connecting case 42: // Empty character screen + string = ""; + text = ControlAction.getText(4, 45, 318, 531, 140); + + if (text) { + for (i = 0; i < text.length; i += 1) { + string += text[i]; + + if (i !== text.length - 1) { + string += " "; + } + } + + if (string === getLocaleString(11161)) { // CDKey disabled from realm play + D2Bot.updateStatus("Realm Disabled CDKey"); + D2Bot.printToConsole("Realm Disabled CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + } + } + if (!locationTimeout(StarterConfig.ConnectingTimeout * 1e3, location)) { ControlAction.click(6, 33, 572, 128, 35); - } - if (gameInfo.rdBlocker) { - D2Bot.restart(); + if (gameInfo.rdBlocker) { + D2Bot.restart(); + } } break; @@ -702,6 +775,7 @@ JoinLoop2: case 38: // Game is full D2Bot.printToConsole("Game is full"); ControlAction.click(6, 652, 469, 120, 20); + lastGame.push(joinInfo.gameName); lastGameStatus = "ready"; @@ -716,4 +790,4 @@ JoinLoop2: break; } -} +} \ No newline at end of file diff --git a/d2bs/kolbot/D2BotLead.dbj b/d2bs/kolbot/D2BotLead.dbj index d87d4e1ae..d032b4a11 100644 --- a/d2bs/kolbot/D2BotLead.dbj +++ b/d2bs/kolbot/D2BotLead.dbj @@ -67,6 +67,7 @@ include("json2.js"); include("OOG.js"); include("automule.js"); include("gambling.js"); +include("craftingsystem.js"); include("torchsystem.js"); include("common/misc.js"); @@ -78,7 +79,6 @@ var gameInfo, gameStart, ingame, chatActionsDone, pingQuit, handle, useChat, firstLogin, connectFail, gameCount = DataFile.getStats().runs + 1, lastGameStatus = "ready", - loginFail = 0, isUp = "no", chanInfo = { joinChannel: "", @@ -114,7 +114,7 @@ function ReceiveCopyData(mode, msg) { break; case 3: // Game request // Don't let others join mule/torch/key/gold drop game - if (AutoMule.inGame || Gambling.inGame || TorchSystem.inGame) { + if (AutoMule.inGame || Gambling.inGame || TorchSystem.inGame || CraftingSystem.inGame) { break; } @@ -188,15 +188,25 @@ function ScriptMsgEvent(msg) { break; case "muleTorch": - AutoMule.torchCheck = true; + AutoMule.torchAnniCheck = 1; + + break; + case "muleAnni": + AutoMule.torchAnniCheck = 2; break; case "torch": TorchSystem.check = true; + break; + case "crafting": + CraftingSystem.check = true; + break; case "getMuleMode": - if (AutoMule.torchCheck) { + if (AutoMule.torchAnniCheck === 2) { + scriptBroadcast("2"); + } else if (AutoMule.torchAnniCheck === 1) { scriptBroadcast("1"); } else if (AutoMule.check) { scriptBroadcast("0"); @@ -267,10 +277,11 @@ function main() { //D2Bot.retrieve(); delay(200); - /*if (!!DataFile.getStats().debugInfo) { - D2Bot.printToConsole("Crash at " + DataFile.getStats().debugInfo, 10); - DataFile.updateStats("debugInfo", false); - }*/ + if (!!DataFile.getStats().debugInfo) { + gameInfo.crashInfo = DataFile.getStats().debugInfo; + + D2Bot.printToConsole("Crash Info: Script: " + JSON.parse(gameInfo.crashInfo).currScript + " Area: " + JSON.parse(gameInfo.crashInfo).area, 10); + } /*if (gameInfo.crashInfo) { D2Bot.printToConsole("Crash Info: Script: " + gameInfo.crashInfo.currScript + " Area: " + gameInfo.crashInfo.area + (gameInfo.crashInfo.hasOwnProperty("lastAction") ? " " + gameInfo.crashInfo.lastAction : ""), 10); @@ -281,6 +292,7 @@ function main() { } //D2Bot.store(JSON.stringify({currScript: "none", area: "out of game"})); + DataFile.updateStats("debugInfo", JSON.stringify({currScript: "none", area: "out of game"})); while (true) { while (me.ingame) { // returns true before actually in game so we can't only use this check @@ -291,7 +303,7 @@ function main() { gameStart = getTickCount(); print("Updating Status"); - D2Bot.updateStatus("Game: " + me.gamename); + //D2Bot.updateStatus("Game: " + me.gamename); lastGameStatus = "ingame"; ingame = true; @@ -300,6 +312,7 @@ function main() { DataFile.updateStats("ingameTick"); } + D2Bot.updateStatus("Game: " + me.gamename + timer(gameStart)); } delay(1000); @@ -322,12 +335,14 @@ MainSwitch: case 1: // Lobby D2Bot.updateStatus("Lobby"); + if (!firstLogin) { + firstLogin = true; + } + if (lastGameStatus === "pending") { gameCount += 1; } - loginFail = 0; - if (StarterConfig.PingQuitDelay && pingQuit) { ControlAction.timeoutDelay("Ping Delay", StarterConfig.PingQuitDelay * 1e3); @@ -353,7 +368,7 @@ MainSwitch: if (ingame) { //D2Bot.store(JSON.stringify({currScript: "none", area: "out of game"})); - if (AutoMule.outOfGameCheck() || TorchSystem.outOfGameCheck() || Gambling.outOfGameCheck()) { + if (AutoMule.outOfGameCheck() || TorchSystem.outOfGameCheck() || Gambling.outOfGameCheck() || CraftingSystem.outOfGameCheck()) { break; } @@ -412,7 +427,7 @@ MainSwitch: if (ingame) { //D2Bot.store(JSON.stringify({currScript: "none", area: "out of game"})); - if (AutoMule.outOfGameCheck() || TorchSystem.outOfGameCheck() || Gambling.outOfGameCheck()) { + if (AutoMule.outOfGameCheck() || TorchSystem.outOfGameCheck() || Gambling.outOfGameCheck() || CraftingSystem.outOfGameCheck()) { break; } @@ -477,7 +492,7 @@ MainSwitch: if (ControlAction.joinChannel(chanInfo.joinChannel[i])) { useChat = true; } else { - print("�c1Unable to join channel, disabling chat messages."); + print("ÿc1Unable to join channel, disabling chat messages."); useChat = false; } @@ -540,6 +555,8 @@ MainSwitch: // FTJ handler if (lastGameStatus === "pending") { + isUp = "no"; + D2Bot.printToConsole("Failed to create game"); ControlAction.timeoutDelay("FTJ delay", StarterConfig.FTJDelay * 1e3); D2Bot.updateRuns(); @@ -574,10 +591,6 @@ MainSwitch: ControlAction.click(6, 33, 572, 128, 35); } - if (!firstLogin) { - firstLogin = true; - } - D2Bot.updateStatus("Logging In"); try { @@ -607,18 +620,23 @@ MainSwitch: break; case getLocaleString(5208): - loginFail += 1; + D2Bot.updateStatus("Invalid Account"); + D2Bot.printToConsole("Invalid Account"); - if (loginFail < 2) { - ControlAction.timeoutDelay("Login retry", 3000); - ControlAction.click(6, 335, 412, 128, 35); + break; + case getLocaleString(5202): // cd key intended for another product + case getLocaleString(10915): // lod key intended for another product + D2Bot.updateStatus("Invalid CDKey"); + D2Bot.printToConsole("Invalid CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); - break MainSwitch; + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); } - D2Bot.updateStatus("Invalid Account"); - D2Bot.printToConsole("Invalid Account"); - break; case getLocaleString(5199): D2Bot.updateStatus("Disabled CDKey"); @@ -632,6 +650,19 @@ MainSwitch: D2Bot.stop(); } + break; + case getLocaleString(10913): + D2Bot.updateStatus("Disabled LoD CDKey"); + D2Bot.printToConsole("Disabled LoD CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + break; case getLocaleString(5347): D2Bot.updateStatus("Disconnected"); @@ -643,6 +674,13 @@ MainSwitch: D2Bot.updateStatus("Login Error"); D2Bot.printToConsole("Login Error - " + string); + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + break; } } @@ -774,6 +812,32 @@ MainSwitch: break; case 23: // Character Select - Connecting case 42: // Empty character screen + string = ""; + text = ControlAction.getText(4, 45, 318, 531, 140); + + if (text) { + for (i = 0; i < text.length; i += 1) { + string += text[i]; + + if (i !== text.length - 1) { + string += " "; + } + } + + if (string === getLocaleString(11161)) { // CDKey disabled from realm play + D2Bot.updateStatus("Realm Disabled CDKey"); + D2Bot.printToConsole("Realm Disabled CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + } + } + if (!locationTimeout(StarterConfig.ConnectingTimeout * 1e3, location)) { ControlAction.click(6, 33, 572, 128, 35); @@ -832,4 +896,4 @@ MainSwitch: break; } -} +} \ No newline at end of file diff --git a/d2bs/kolbot/D2BotMule.dbj b/d2bs/kolbot/D2BotMule.dbj index cebff13b6..ae7276961 100644 --- a/d2bs/kolbot/D2BotMule.dbj +++ b/d2bs/kolbot/D2BotMule.dbj @@ -9,7 +9,7 @@ var StarterConfig = { }; -var master, gameInfo, connectFail, makeAcc, +var master, gameInfo, connectFail, makeAcc, joinInfo, muleMode, muleFilename, muleObj, handle, makeNext = false, status = "loading", @@ -77,26 +77,30 @@ function pickItems() { rval = "fail", list = []; - while (!me.ingame && !me.gameReady) { - delay(500); + while (!me.name || !me.gameReady) { + if (!me.ingame) { + return rval; + } + + delay(100); } - delay(1000); + //delay(1000); - for (i = 0; i < 10; i += 1) { - items = me.getItems(); + for (i = 0; i < 100; i += 1) { + items = me.findItems(-1, 0, 3); if (items) { break; } - delay(1000); + delay(100); } if (items) { for (i = 0; i < items.length; i += 1) { if (items[i].mode === 0 && items[i].location === 3 && Town.ignoredItemTypes.indexOf(items[i].itemType) > -1 // drop trash (id/tp scroll primarily) - && (muleMode !== 1 || items[i].classid !== 530)) { // don't drop ID scroll with torch mules + && (muleMode === 0 || items[i].classid !== 530)) { // don't drop ID scroll with torch/anni mules try { items[i].drop(); } catch (dropError) { @@ -108,11 +112,11 @@ function pickItems() { while (me.gameReady) { if (masterStatus.status === "done") { - item = getUnit(4, -1, 3); // item, on ground + item = getUnit(4); if (item) { do { - if (Town.ignoredItemTypes.indexOf(item.itemType) === -1) { // don't pick up trash + if (getDistance(me, item) < 20 && [3, 5].indexOf(item.mode) > -1 && Town.ignoredItemTypes.indexOf(item.itemType) === -1) { // don't pick up trash list.push(copyUnit(item)); } } while (item.getNext()); @@ -130,12 +134,19 @@ function pickItems() { canFit = Storage.Inventory.CanFit(item); // Torch handling - if (muleMode === 1 && item.classid === 604 && item.quality === 7 && !Pickit.canPick(item)) { + if (muleMode > 0 && item.classid === 604 && item.quality === 7 && !Pickit.canPick(item)) { D2Bot.printToConsole("Mule already has a Torch.", 7); rval = "next"; } + // Anni handling + if (muleMode > 0 && item.classid === 603 && item.quality === 7 && !Pickit.canPick(item)) { + D2Bot.printToConsole("Mule already has an Anni.", 7); + + rval = "next"; + } + if (!canFit) { stashItems(); @@ -157,7 +168,7 @@ function pickItems() { //D2Bot.shoutGlobal("report", 0); } - delay(1000); + delay(500); } return rval; @@ -176,7 +187,11 @@ function ReceiveCopyData(mode, msg) { // mode check instead of msg check because of crashes switch (mode) { - case 1: // join + case 1: // JoinInfo + //print("Got Join Info"); + + joinInfo = JSON.parse(msg); + break; case 2: // game info print("Recieved Game Info"); @@ -281,6 +296,24 @@ function locationTimeout(time, location) { return (getLocation() !== location); } +function ingameTimeout(time) { + var tick = getTickCount(); + + while (getTickCount() - tick < time) { + if (me.ingame && me.gameReady) { + return true; + } + + if (getLocation() === 28) { // game doesn't exist, might need more locs + break; + } + + delay(100); + } + + return me.ingame && me.gameReady; +} + function timeoutDelay(text, time) { var endTime = getTickCount() + time; @@ -309,33 +342,12 @@ function updateCount() { ControlAction.click(6, 33, 572, 128, 35); } -function checkTorch() { +function checkAnniTorch() { while (!me.gameReady) { delay(500); } - var item = me.getItem("cm2"); - - if (item) { - do { - if (item.quality === 7) { - return true; - } - } while (item.getNext()); - } - - // Hacky anni add-on - item = me.getItem("cm1"); - - if (item) { - do { - if (item.quality === 7) { - return true; - } - } while (item.getNext()); - } - - return false; + return me.findItem(603, 0, -1, 7) || me.findItem(604, 0, -1, 7); } function foreverAlone() { @@ -358,6 +370,7 @@ include("automule.js"); include("mulelogger.js"); include("torchsystem.js"); include("NTItemParser.dbl"); +include("common/attack.js"); include("common/storage.js"); include("common/pickit.js"); include("common/town.js"); @@ -383,17 +396,30 @@ function main() { delay(500); } + if (gameInfo.rdBlocker) { + D2Bot.printToConsole("You must disable RD Blocker for Mule Logger to work properly. Stopping."); + D2Bot.stop(me.profile, true); + + return; + } + + D2Bot.updateRuns(); // we need the mule to swap keys somehow after all + delay(1000); + // Wait for master before login = give room to determine muling mode (normal or torch) while (!master) { - delay(1000); + delay(100); } print("Master found: " + master); muleObj = AutoMule.getMuleObject(muleMode, master); - muleFilename = AutoMule.getMuleFilename(muleMode); + muleFilename = AutoMule.getMuleFilename(muleMode, master); + + print("Mule filename: " + muleFilename); - var obj, statusTimeout; + var obj, tick, + inGame = false; try { // ugly solution to uglier problem - pickItem area update @@ -414,27 +440,39 @@ function main() { } catch (e) { print("Caught exception creating data files."); print(e); - D2Bot.printToConsole("Exception: " + e); + D2Bot.printToConsole("DataFileException: " + e.message + " (" + e.fileName.substring(e.fileName.lastIndexOf("\\") + 1, e.fileName.length) + " #" + e.lineNumber + ")"); } while (true) { try { if (me.ingame && me.gameReady) { - if (status === "loading") { - status = "ready"; + if (!inGame) { + if (status !== "begin") { + status = "ready"; + } - D2Bot.updateStatus("In " + (muleMode ? "torch" : "") + " mule game."); - D2Bot.printToConsole("In " + (muleMode ? "torch" : "") + " mule game.", 7); + D2Bot.updateStatus("In " + (muleMode === 2 ? "anni" : muleMode === 1 ? "torch" : "") + " mule game."); + D2Bot.printToConsole("In " + (muleMode === 2 ? "anni" : muleMode === 1 ? "torch" : "") + " mule game.", 7); Storage.Init(); + + inGame = true; } - for (statusTimeout = 0; statusTimeout < 60000 && status !== "begin"; statusTimeout += 500) { - delay(500); + tick = getTickCount(); + + while (getTickCount() - tick < 60000) { + if (status === "begin") { + break; + } + + delay(100); } + //print("Delay: " + (getTickCount() - tick)); + if (status !== "begin") { D2Bot.printToConsole("Nobody joined - stopping.", 9); - D2Bot.stop(); + D2Bot.stop(me.profile, true); } me.overhead("begin"); @@ -446,26 +484,26 @@ function main() { obj = MuleData.read(); - if (checkTorch()) { + if (checkAnniTorch()) { obj.torchChars.push(me.name); } MuleData.write(obj); D2Bot.printToConsole("Done muling.", 7); sendCopyData(null, master, 10, JSON.stringify({status: "quit"})); - delay(500); - D2Bot.stop(); + //delay(500); + D2Bot.stop(me.profile, true); - break; + return; // can't fit more items, get to next character or account case "next": MuleLogger.logChar(); - delay(500); + //delay(500); makeNext = true; obj = MuleData.read(); - if (checkTorch()) { + if (checkAnniTorch()) { obj.torchChars.push(me.name); } @@ -475,6 +513,11 @@ function main() { D2Bot.printToConsole("Mule full, getting next character.", 7); quit(); + // TODO: see whether a for loop is better + while (me.ingame) { + delay(100); + } + break; case "fail": // Try again @@ -482,13 +525,17 @@ function main() { } } - locationAction(getLocation()); - delay(1000); + if (!me.ingame) { + delay(1000); + locationAction(getLocation()); + } } catch (e2) { print("Caught an exception in the main loop."); print(e2); - D2Bot.printToConsole("Exception: " + e2); + D2Bot.printToConsole("MainLoopException: " + e2.message + " (" + e2.fileName.substring(e2.fileName.lastIndexOf("\\") + 1, e2.fileName.length) + " #" + e2.lineNumber + ")"); } + + delay(100); } } @@ -497,17 +544,29 @@ function locationAction(location) { MainSwitch: switch (location) { - case 0: - break; case 1: case 3: + D2Bot.updateStatus("Lobby"); + if (makeNext) { ControlAction.click(6, 693, 490, 80, 20); break; } - ControlAction.click(6, 652, 469, 120, 20); // Join + if (!ControlAction.click(6, 652, 469, 120, 20)) { // Join + break; + } + + if (!locationTimeout(5000, location)) { // in case join button gets bugged + if (!ControlAction.click(6, 533, 469, 120, 20)) { // Create + break; + } + + if (!ControlAction.click(6, 652, 469, 120, 20)) { // Join + break; + } + } break; case 4: // Create Game @@ -521,7 +580,7 @@ MainSwitch: delay(2000); createGame(muleObj.muleGameName[0], muleObj.muleGameName[1]); - locationTimeout(5000, location); + ingameTimeout(5000); break; case 2: // Waiting In Line @@ -532,9 +591,17 @@ MainSwitch: break; case 5: // Join Game D2Bot.updateStatus("Join Game"); - delay(2000); - joinGame(muleObj.muleGameName[0], muleObj.muleGameName[1]); - locationTimeout(5000, location); + D2Bot.requestGame(master); + delay(100); + + if (joinInfo && joinInfo.gameName !== "" && joinInfo.inGame) { + joinGame(joinInfo.gameName, joinInfo.gamePass); + } else { + joinGame(muleObj.muleGameName[0], muleObj.muleGameName[1]); + } + + ingameTimeout(5000); + print("Ingame timeout done."); break; case 6: // Ladder @@ -591,16 +658,51 @@ MainSwitch: case getLocaleString(5207): D2Bot.updateStatus("Invalid Password"); D2Bot.printToConsole("Invalid Password"); + + break; + case getLocaleString(5208): + ControlAction.click(6, 335, 412, 128, 35); + + makeAcc = true; + + break MainSwitch; + case getLocaleString(5202): // cd key intended for another product + case getLocaleString(10915): // lod key intended for another product + D2Bot.updateStatus("Invalid CDKey"); + D2Bot.printToConsole("Invalid CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(me.profile, true); + } + break; case getLocaleString(5199): D2Bot.updateStatus("Disabled CDKey"); - D2Bot.printToConsole("Disabled CDKey"); + D2Bot.printToConsole("Disabled CDKey: " + gameInfo.mpq, 6); D2Bot.CDKeyDisabled(); if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); } else { - D2Bot.stop(); + D2Bot.stop(me.profile, true); + } + + break; + case getLocaleString(10913): + D2Bot.updateStatus("Disabled LoD CDKey"); + D2Bot.printToConsole("Disabled LoD CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(me.profile, true); } break; @@ -609,16 +711,18 @@ MainSwitch: D2Bot.printToConsole("Disconnected"); ControlAction.click(6, 335, 412, 128, 35); - break MainSwitch; - case getLocaleString(5208): - ControlAction.click(6, 335, 412, 128, 35); - - makeAcc = true; - break MainSwitch; default: D2Bot.updateStatus("Login Error"); D2Bot.printToConsole("Login Error - " + string); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(me.profile, true); + } + break; } } @@ -681,7 +785,34 @@ MainSwitch: case 15: // new character (selected) case 29: // new character (list) case 42: // empty char screen + string = ""; + text = ControlAction.getText(4, 45, 318, 531, 140); + + if (text) { + for (i = 0; i < text.length; i += 1) { + string += text[i]; + + if (i !== text.length - 1) { + string += " "; + } + } + + if (string === getLocaleString(11161)) { // CDKey disabled from realm play + D2Bot.updateStatus("Realm Disabled CDKey"); + D2Bot.printToConsole("Realm Disabled CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(me.profile, true); + } + } + } + // Single Player screen fix + // TODO: see if this is still needed. d2bs doesn't load scripts twice anymore if (getLocation() === 12 && !getControl(4, 626, 100, 151, 44)) { ControlAction.click(6, 33, 572, 128, 35); @@ -713,7 +844,7 @@ MainSwitch: obj = MuleData.read(); if (makeNext) { - if (obj.fullChars.length === 8 || (muleMode === 1 && obj.torchChars.length === 8)) { + if (obj.fullChars.length === 8 || (muleMode > 0 && obj.torchChars.length === 8)) { ControlAction.click(6, 33, 572, 128, 35); nextAccount(); @@ -738,7 +869,7 @@ MainSwitch: charClass: "amazon" }; - if (muleMode === 1 && obj.torchChars.indexOf(info.charName) > -1) { + if (muleMode > 0 && obj.torchChars.indexOf(info.charName) > -1) { nextChar(); break; @@ -777,15 +908,15 @@ MainSwitch: break; case 19: // Login - Cdkey In Use - D2Bot.printToConsole("CD-Key in use by " + ControlAction.getText(4, 158, 310, 485, 40)); + D2Bot.printToConsole(gameInfo.mpq + " is in use by " + ControlAction.getText(4, 158, 310, 485, 40), 6); D2Bot.CDKeyInUse(); if (gameInfo.switchKeys) { - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); } else { ControlAction.click(6, 335, 450, 128, 35); - timeoutDelay("CD-Key in use", StarterConfig.CDKeyInUseDelay * 6e4); + ControlAction.timeoutDelay("CD-Key in use", StarterConfig.CDKeyInUseDelay * 6e4); } break; @@ -813,26 +944,26 @@ MainSwitch: switch (string) { case getLocaleString(10914): - D2Bot.printToConsole("LoD key in use by " + ControlAction.getText(4, 158, 310, 485, 40)); + D2Bot.printToConsole(gameInfo.mpq + " LoD key in use by " + ControlAction.getText(4, 158, 310, 485, 40), 6); D2Bot.CDKeyInUse(); if (gameInfo.switchKeys) { - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); } else { ControlAction.click(6, 335, 450, 128, 35); - timeoutDelay("LoD key in use", StarterConfig.CDKeyInUseDelay * 6e4); + ControlAction.timeoutDelay("LoD key in use", StarterConfig.CDKeyInUseDelay * 6e4); } break; default: if (gameInfo.switchKeys) { D2Bot.printToConsole("Invalid CD-Key"); - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); } else { ControlAction.click(6, 335, 450, 128, 35); - timeoutDelay("Invalid CD-Key", StarterConfig.CDKeyInUseDelay * 6e4); + ControlAction.timeoutDelay("Invalid CD-Key", StarterConfig.CDKeyInUseDelay * 6e4); } break; diff --git a/d2bs/kolbot/D2BotMuleLog.dbj b/d2bs/kolbot/D2BotMuleLog.dbj index c0678bcab..73655f8fe 100644 --- a/d2bs/kolbot/D2BotMuleLog.dbj +++ b/d2bs/kolbot/D2BotMuleLog.dbj @@ -118,13 +118,28 @@ function main() { delay(500); } + if (gameInfo.rdBlocker) { + D2Bot.printToConsole("You must disable RD Blocker for Mule Logger to work properly. Stopping."); + D2Bot.stop(); + + return; + } + parseInfo(); - if (gameInfo.error === "@error") { - timeoutDelay("Crash Delay", StarterConfig.CrashDelay * 1e3); + if (gameInfo.error) { + if (!!DataFile.getStats().debugInfo) { + gameInfo.crashInfo = DataFile.getStats().debugInfo; + + D2Bot.printToConsole("Crash Info: Script: " + JSON.parse(gameInfo.crashInfo).currScript + " Area: " + JSON.parse(gameInfo.crashInfo).area, 10); + } + + ControlAction.timeoutDelay("Crash Delay", StarterConfig.CrashDelay * 1e3); D2Bot.updateRuns(); } + DataFile.updateStats("debugInfo", JSON.stringify({currScript: "none", area: "out of game"})); + while (true) { while (me.ingame) { // returns true before actually in game so we can't only use this check if (me.gameReady) { // returns false when switching acts so we can't use while @@ -167,12 +182,13 @@ MainSwitch: print("updating runs"); D2Bot.updateRuns(); + delay(1000); gameCount += 1; lastGameStatus = "ready"; ingame = false; - ControlAction.click(6, 693, 490, 80, 20); + ControlAction.click(6, 693, 490, 80, 20); // Quit from Lobby break; } @@ -300,14 +316,41 @@ MainSwitch: D2Bot.updateStatus("Invalid Account"); D2Bot.printToConsole("Invalid Account"); + break; + case getLocaleString(5202): // cd key intended for another product + case getLocaleString(10915): // lod key intended for another product + D2Bot.updateStatus("Invalid CDKey"); + D2Bot.printToConsole("Invalid CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + break; case getLocaleString(5199): D2Bot.updateStatus("Disabled CDKey"); - D2Bot.printToConsole("Disabled CDKey"); + D2Bot.printToConsole("Disabled CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + + break; + case getLocaleString(10913): + D2Bot.updateStatus("Disabled LoD CDKey"); + D2Bot.printToConsole("Disabled LoD CDKey: " + gameInfo.mpq, 6); D2Bot.CDKeyDisabled(); if (gameInfo.switchKeys) { - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); } else { D2Bot.stop(); @@ -324,6 +367,13 @@ MainSwitch: D2Bot.updateStatus("Login Error"); D2Bot.printToConsole("Login Error - " + string); + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + break; } } @@ -375,9 +425,7 @@ MainSwitch: if (obj.currChar) { for (i = 0; i < charList.length; i += 1) { if (charList[i] === obj.currChar) { - charList.splice(0, i); - - i -= 1; + charList.splice(0, i + 1); // Remove the previous currChar as well break; } @@ -385,14 +433,16 @@ MainSwitch: } } - currChar = charList.shift(); - obj.currChar = currChar; - // last char in acc = trigger next acc if (!charList.length) { nextAcc = true; + + break; } + currChar = charList.shift(); + obj.currChar = currChar; + print("ÿc4Mule Loggerÿc2: Login character: " + currChar); FileTools.writeText("logs/MuleLog.json", JSON.stringify(obj)); ControlAction.loginCharacter({charName: currChar}); @@ -436,15 +486,15 @@ MainSwitch: ControlAction.click(6, 351, 337, 96, 32); break; case 19: // Login - Cdkey In Use - D2Bot.printToConsole("CD-Key in use by " + ControlAction.getText(4, 158, 310, 485, 40)); + D2Bot.printToConsole(gameInfo.mpq + " is in use by " + ControlAction.getText(4, 158, 310, 485, 40), 6); D2Bot.CDKeyInUse(); if (gameInfo.switchKeys) { - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); } else { ControlAction.click(6, 335, 450, 128, 35); - timeoutDelay("CD-Key in use", StarterConfig.CDKeyInUseDelay * 6e4); + ControlAction.timeoutDelay("CD-Key in use", StarterConfig.CDKeyInUseDelay * 6e4); } break; @@ -472,26 +522,26 @@ MainSwitch: switch (string) { case getLocaleString(10914): - D2Bot.printToConsole("LoD key in use by " + ControlAction.getText(4, 158, 310, 485, 40)); + D2Bot.printToConsole(gameInfo.mpq + " LoD key in use by " + ControlAction.getText(4, 158, 310, 485, 40), 6); D2Bot.CDKeyInUse(); if (gameInfo.switchKeys) { - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); } else { ControlAction.click(6, 335, 450, 128, 35); - timeoutDelay("LoD key in use", StarterConfig.CDKeyInUseDelay * 6e4); + ControlAction.timeoutDelay("LoD key in use", StarterConfig.CDKeyInUseDelay * 6e4); } break; default: if (gameInfo.switchKeys) { D2Bot.printToConsole("Invalid CD-Key"); - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); } else { ControlAction.click(6, 335, 450, 128, 35); - timeoutDelay("Invalid CD-Key", StarterConfig.CDKeyInUseDelay * 6e4); + ControlAction.timeoutDelay("Invalid CD-Key", StarterConfig.CDKeyInUseDelay * 6e4); } break; @@ -534,6 +584,33 @@ MainSwitch: break; case 42: // Empty character screen + // TODO: see if this is needed in case 12 too + string = ""; + text = ControlAction.getText(4, 45, 318, 531, 140); + + if (text) { + for (i = 0; i < text.length; i += 1) { + string += text[i]; + + if (i !== text.length - 1) { + string += " "; + } + } + + if (string === getLocaleString(11161)) { // CDKey disabled from realm play + D2Bot.updateStatus("Realm Disabled CDKey"); + D2Bot.printToConsole("Realm Disabled CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + } + } + if (!locationTimeout(5000, location)) { nextAcc = true; // Go to next account diff --git a/d2bs/kolbot/D2BotPubJoin.dbj b/d2bs/kolbot/D2BotPubJoin.dbj new file mode 100644 index 000000000..3495f2d85 --- /dev/null +++ b/d2bs/kolbot/D2BotPubJoin.dbj @@ -0,0 +1,789 @@ +var StarterConfig = { + MinGameTime: 0, // Minimum game length in seconds. If a game is ended too soon, the rest of the time is waited in the lobby + PingQuitDelay: 30, // Time in seconds to wait in lobby after quitting due to high ping + CreateGameDelay: 5, // Seconds to wait before creating a new game + ResetCount: 0, // Reset game count back to 1 every X games. + CharacterDifference: 99, // Character level difference. Set to false to disable character difference. + ChatActionsDelay: 2, // Seconds to wait in lobby before entering a channel + + JoinChannel: "", // Default channel. Can be an array of channels - ["channel 1", "channel 2"] + FirstJoinMessage: "", // Default join message. Can be an array of messages + AnnounceGames: false, // Default value + AfterGameMessage: "", // Default message after a finished game. Can be an array of messages + + SwitchKeyDelay: 5, // Seconds to wait before switching a used/banned key or after realm down + CrashDelay: 5, // Seconds to wait after a d2 window crash + FTJDelay: 10, // Seconds to wait after failing to create a game + RealmDownDelay: 2, // Minutes to wait after getting Realm Down message + UnableToConnectDelay: 5, // Minutes to wait after Unable To Connect message + CDKeyInUseDelay: 5, // Minutes to wait before connecting again if CD-Key is in use. + ConnectingTimeout: 20, // Seconds to wait before cancelling the 'Connecting...' screen + PleaseWaitTimeout: 10, // Seconds to wait before cancelling the 'Please Wait...' screen + WaitInLineTimeout: 60, // Seconds to wait before cancelling the 'Waiting in Line...' screen + GameDoesNotExistTimeout: 30 // Seconds to wait before cancelling the 'Game does not exist.' screen +}; + +/** + IncludeFilter config: + + Multiple entries in the same array mean AND: + ["baal", "-"] = game has to contain "baal" and "-" + + Different entries mean OR: + ["baal"], + ["diablo"] + will join games with either "baal" or "diablo" in their name + + Similar rules apply to ExcludeFilter: + + ["somebaal", "-"] ignores games with "somebaal" and "-" in the game name + + ["somebaal"], + ["somediablo"] + this will ignore all games with "somebaal" or "somediablo" in their names +*/ + +var IncludeFilter = [ + [""] +]; + +var ExcludeFilter = [ + [""] +]; + +// ############################################################################### + +function includeCheck(game) { + // No filters + if (!IncludeFilter.length) { + return true; + } + + var i, j; + + for (i = 0; i < IncludeFilter.length; i += 1) { + for (j = 0; j < IncludeFilter[i].length; j += 1) { + // Break the inner loop if an element didn't match or if an element is invalid + if (!IncludeFilter[i][j] || !game.match(IncludeFilter[i][j], "gi")) { + break; + } + } + + // All elements matched + if (j === IncludeFilter[i].length) { + return true; + } + } + + return false; +} + +function excludeCheck(game) { + // No filters + if (!ExcludeFilter.length) { + return true; + } + + var i, j; + + for (i = 0; i < ExcludeFilter.length; i += 1) { + for (j = 0; j < ExcludeFilter[i].length; j += 1) { + // Break the inner loop if an element didn't match or if an element is invalid + if (!ExcludeFilter[i][j] || !game.match(ExcludeFilter[i][j], "gi")) { + break; + } + } + + // All elements matched + if (j === ExcludeFilter[i].length) { + return false; + } + } + + return true; +} + +// No touchy! +include("json2.js"); +include("OOG.js"); +include("automule.js"); +include("gambling.js"); +include("craftingsystem.js"); +include("torchsystem.js"); +include("common/misc.js"); + +if (!FileTools.exists("data/" + me.profile + ".json")) { + DataFile.create(); +} + +var gameInfo, gameStart, ingame, chatActionsDone, pingQuit, + handle, useChat, firstLogin, connectFail, lastGameTick, + gameCount = DataFile.getStats().runs + 1, + lastGameStatus = "ready", + loginFail = 0, + isUp = "no", + chanInfo = { + joinChannel: "", + firstMsg: "", + afterMsg: "", + announce: false + }; + +function sayMsg(string) { + if (!useChat) { + return; + } + + say(string); +} + +function ReceiveCopyData(mode, msg) { + var obj; + + switch (msg) { + case "Handle": + handle = mode; + + break; + } + + switch (mode) { + case 2: // Game info + print("Recieved Game Info"); + + gameInfo = JSON.parse(msg); + + break; + case 3: // Game request + // Don't let others join mule/torch/key/gold drop game + if (AutoMule.inGame || Gambling.inGame || TorchSystem.inGame || CraftingSystem.inGame) { + break; + } + + if (gameInfo) { + obj = JSON.parse(msg); + + if (me.gameReady) { + D2Bot.joinMe(obj.profile, me.gamename.toLowerCase(), "", me.gamepassword.toLowerCase(), isUp); + } else { + D2Bot.joinMe(obj.profile, gameInfo.gameName.toLowerCase(), gameCount, gameInfo.gamePass.toLowerCase(), isUp); + } + } + + break; + case 4: // Heartbeat ping + if (msg === "pingreq") { + sendCopyData(null, me.windowtitle, 4, "pingrep"); + } + + break; + case 0xf124: // Cached info retreival + if (msg !== "null") { + gameInfo.crashInfo = JSON.parse(msg); + } + + break; + } +} + +function setNextGame() { + var nextGame = gameInfo.gameName; + + if (StarterConfig.ResetCount && gameCount + 1 >= StarterConfig.ResetCount) { + nextGame += 1; + } else { + nextGame += (gameCount + 1); + } + + DataFile.updateStats("nextGame", nextGame); +} + +function locationTimeout(time, location) { + var endtime = getTickCount() + time; + + while (getLocation() === location && endtime > getTickCount()) { + delay(500); + } + + return (getLocation() !== location); +} + +function updateCount() { + D2Bot.updateCount(); + delay(1000); + ControlAction.click(6, 264, 366, 272, 35); + + try { + login(me.profile); + } catch (e) { + + } + + delay(1000); + ControlAction.click(6, 33, 572, 128, 35); +} + +function ScriptMsgEvent(msg) { + switch (msg) { + case "mule": + AutoMule.check = true; + + break; + case "muleTorch": + AutoMule.torchCheck = true; + + break; + case "torch": + TorchSystem.check = true; + + break; + case "crafting": + CraftingSystem.check = true; + + break; + case "getMuleMode": + if (AutoMule.torchAnniCheck === 2) { + scriptBroadcast("2"); + } else if (AutoMule.torchAnniCheck === 1) { + scriptBroadcast("1"); + } else if (AutoMule.check) { + scriptBroadcast("0"); + } + + break; + case "pingquit": + pingQuit = true; + + break; + } +} + +function timer(tick) { + if (!tick) { + return ""; + } + + var min, sec; + + min = Math.floor((getTickCount() - tick) / 60000).toString(); + + if (min <= 9) { + min = "0" + min; + } + + sec = (Math.floor((getTickCount() - tick) / 1000) % 60).toString(); + + if (sec <= 9) { + sec = "0" + sec; + } + + return " (" + min + ":" + sec + ")"; +} + +function randomString(len) { + var i, + rval = "", + letters = "abcdefghijklmnopqrstuvwxyz"; + + for (i = 0; i < len; i += 1) { + rval += letters[Math.floor(Math.random() * 26)]; + } + + return rval; +} + +function main() { + debugLog(me.profile); + addEventListener('copydata', ReceiveCopyData); + addEventListener('scriptmsg', ScriptMsgEvent); + + while (!handle) { + delay(100); + } + + DataFile.updateStats("handle", handle); + delay(500); + D2Bot.init(); + load("tools/heartbeat.js"); + + while (!gameInfo) { + D2Bot.requestGameInfo(); + delay(500); + } + + if (gameInfo.error) { + D2Bot.retrieve(); + delay(200); + + if (gameInfo.crashInfo) { + D2Bot.printToConsole("Crash Info: Script: " + gameInfo.crashInfo.currScript + " Area: " + gameInfo.crashInfo.area, 10); + } + + ControlAction.timeoutDelay("Crash Delay", StarterConfig.CrashDelay * 1e3); + D2Bot.updateRuns(); + } + + D2Bot.store(JSON.stringify({currScript: "none", area: "out of game"})); + + while (true) { + while (me.ingame) { // returns true before actually in game so we can't only use this check + if (me.gameReady) { // returns false when switching acts so we can't use while + isUp = "yes"; + + if (!ingame) { + gameStart = getTickCount(); + + print("Updating Status"); + //D2Bot.updateStatus("Game: " + me.gamename); + + lastGameStatus = "ingame"; + ingame = true; + + DataFile.updateStats("runs", gameCount); + DataFile.updateStats("ingameTick"); + } + + D2Bot.updateStatus("Game: " + me.gamename + timer(gameStart)); + } + + delay(1000); + } + + isUp = "no"; + + locationAction(getLocation()); + delay(1000); + } +} + +function locationAction(location) { + var i, string, text, gameToJoin, doneGames, gameList; + +MainSwitch: + switch (location) { + case 0: + break; + case 1: // Lobby + D2Bot.updateStatus("Lobby"); + + if (!firstLogin) { + firstLogin = true; + } + + if (lastGameStatus === "pending") { + gameCount += 1; + } + + loginFail = 0; + + if (StarterConfig.PingQuitDelay && pingQuit) { + ControlAction.timeoutDelay("Ping Delay", StarterConfig.PingQuitDelay * 1e3); + + pingQuit = false; + } + + if (ingame || gameInfo.error) { + if (!gameStart) { + gameStart = DataFile.getStats().ingameTick; + } + + if (getTickCount() - gameStart < StarterConfig.MinGameTime * 1e3) { + ControlAction.timeoutDelay("Min game time wait", StarterConfig.MinGameTime * 1e3 + gameStart - getTickCount()); + } + } + + if (ingame) { + D2Bot.store(JSON.stringify({currScript: "none", area: "out of game"})); + + if (AutoMule.outOfGameCheck() || TorchSystem.outOfGameCheck() || Gambling.outOfGameCheck() || CraftingSystem.outOfGameCheck()) { + break; + } + + print("updating runs"); + D2Bot.updateRuns(); + + lastGameTick = getTickCount(); + gameCount += 1; + lastGameStatus = "ready"; + ingame = false; + + if (StarterConfig.ResetCount && gameCount >= StarterConfig.ResetCount) { + gameCount = 1; + + DataFile.updateStats("runs", gameCount); + } + } + + if (!ControlAction.click(6, 652, 469, 120, 20)) { // Join + break; + } + + if (!locationTimeout(5000, location)) { // in case create button gets bugged + if (!ControlAction.click(6, 533, 469, 120, 20)) { // Create + break; + } + + if (!ControlAction.click(6, 652, 469, 120, 20)) { // Join + break; + } + } + + break; + case 2: // Waiting In Line + D2Bot.updateStatus("Waiting..."); + locationTimeout(StarterConfig.WaitInLineTimeout * 1e3, location); + ControlAction.click(6, 433, 433, 96, 32); + + break; + case 3: // Lobby Chat + break; + case 4: // Create Game + break; + case 5: // Join Game + // Don't join immediately after previous game to avoid FTJ + if (getTickCount() - lastGameTick < 5000) { + ControlAction.timeoutDelay("Game Delay", (lastGameTick - getTickCount() + 5000)); + } + + for (i = 0; i < 5; i += 1) { + gameList = ControlAction.getGameList(); + + if (gameList && gameList.length > 0) { + break; + } + + delay(1000); + } + + if (gameList) { + doneGames = []; + gameToJoin = false; + + if (FileTools.exists("logs/doneGames.json")) { + doneGames = JSON.parse(Misc.fileAction("logs/doneGames.json", 0)); + } + + gameList.sort(function (a, b) { + return b.players - a.players; + }); + + for (i = 0; i < gameList.length; i += 1) { + if (doneGames.indexOf(gameList[i].gameName) === -1 && includeCheck(gameList[i].gameName) && excludeCheck(gameList[i].gameName)) { + print("ÿc7Game: " + gameList[i].gameName + ", Players: " + gameList[i].players); + + gameToJoin = gameList[i].gameName; + + break; + } + } + + if (gameToJoin) { + if (doneGames.length >= 20) { + doneGames.shift(); + } + + doneGames.push(gameToJoin); + Misc.fileAction("logs/doneGames.json", 1, JSON.stringify(doneGames)); + + me.blockMouse = true; + + try { + joinGame(gameToJoin, ""); + } catch (joinErr) { + + } + + me.blockMouse = false; + + locationTimeout(5000, location); + } + } + + break; + case 6: // Ladder + break; + case 7: // Channel List + break; + case 8: // Main Menu + case 9: // Login + case 12: // Character Select + case 18: // D2 Splash + // Single Player screen fix + if (getLocation() === 12 && !getControl(4, 626, 100, 151, 44)) { + ControlAction.click(6, 33, 572, 128, 35); + + break; + } + + if (firstLogin && getLocation() === 9) { // multiple realm botting fix in case of R/D or disconnect + ControlAction.click(6, 33, 572, 128, 35); + } + + D2Bot.updateStatus("Logging In"); + + try { + login(me.profile); + } catch (e) { + print(e + " " + getLocation()); + } + + break; + case 10: // Login Error + string = ""; + text = ControlAction.getText(4, 199, 377, 402, 140); + + if (text) { + for (i = 0; i < text.length; i += 1) { + string += text[i]; + + if (i !== text.length - 1) { + string += " "; + } + } + + switch (string) { + case getLocaleString(5207): + D2Bot.updateStatus("Invalid Password"); + D2Bot.printToConsole("Invalid Password"); + + break; + case getLocaleString(5208): + loginFail += 1; + + if (loginFail < 2) { + ControlAction.timeoutDelay("Login retry", 3000); + ControlAction.click(6, 335, 412, 128, 35); + + break MainSwitch; + } + + D2Bot.updateStatus("Invalid Account"); + D2Bot.printToConsole("Invalid Account"); + + break; + case getLocaleString(5199): + D2Bot.updateStatus("Disabled CDKey"); + D2Bot.printToConsole("Disabled CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + + break; + case getLocaleString(10913): + D2Bot.updateStatus("Disabled LoD CDKey"); + D2Bot.printToConsole("Disabled LoD CDKey: " + gameInfo.mpq, 6); + D2Bot.CDKeyDisabled(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + + break; + case getLocaleString(5347): + D2Bot.updateStatus("Disconnected"); + D2Bot.printToConsole("Disconnected"); + ControlAction.click(6, 335, 412, 128, 35); + + break MainSwitch; + default: + D2Bot.updateStatus("Login Error"); + D2Bot.printToConsole("Login Error - " + string); + + break; + } + } + + ControlAction.click(6, 335, 412, 128, 35); + + while (true) { + delay(1000); + } + + break; + case 11: // Unable To Connect + D2Bot.updateStatus("Unable To Connect"); + + if (connectFail) { + ControlAction.timeoutDelay("Unable to Connect", StarterConfig.UnableToConnectDelay * 6e4); + + connectFail = false; + } + + if (!ControlAction.click(6, 335, 450, 128, 35)) { + break; + } + + connectFail = true; + + break; + case 13: // Realm Down - Character Select screen + D2Bot.updateStatus("Realm Down"); + delay(1000); + + if (!ControlAction.click(6, 33, 572, 128, 35)) { + break; + } + + updateCount(); + ControlAction.timeoutDelay("Realm Down", StarterConfig.RealmDownDelay * 6e4); + D2Bot.CDKeyRD(); + + if (gameInfo.switchKeys && !gameInfo.rdBlocker) { + D2Bot.printToConsole("Realm Down - Changing CD-Key"); + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.printToConsole("Realm Down - Restart"); + D2Bot.restart(); + } + + break; + case 14: // Character Select / Main Menu - Disconnected + D2Bot.updateStatus("Disconnected"); + delay(500); + ControlAction.click(6, 351, 337, 96, 32); + + break; + case 16: // Character Select - Please Wait popup + if (!locationTimeout(StarterConfig.PleaseWaitTimeout * 1e3, location)) { + ControlAction.click(6, 351, 337, 96, 32); + } + + break; + case 17: // Lobby - Lost Connection - just click okay, since we're toast anyway + delay(1000); + ControlAction.click(6, 351, 337, 96, 32); + + break; + case 19: // Login - Cdkey In Use + D2Bot.printToConsole(gameInfo.mpq + " is in use by " + ControlAction.getText(4, 158, 310, 485, 40), 6); + D2Bot.CDKeyInUse(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + ControlAction.click(6, 335, 450, 128, 35); + ControlAction.timeoutDelay("CD-Key in use", StarterConfig.CDKeyInUseDelay * 6e4); + } + + break; + case 20: // Single Player - Select Difficulty + break; + case 21: // Main Menu - Connecting + if (!locationTimeout(StarterConfig.ConnectingTimeout * 1e3, location)) { + ControlAction.click(6, 330, 416, 128, 35); + } + + break; + case 22: // Login - Invalid Cdkey (classic or xpac) + text = ControlAction.getText(4, 162, 270, 477, 50); + string = ""; + + if (text) { + for (i = 0; i < text.length; i += 1) { + string += text[i]; + + if (i !== text.length - 1) { + string += " "; + } + } + } + + switch (string) { + case getLocaleString(10914): + D2Bot.printToConsole(gameInfo.mpq + " LoD key in use by " + ControlAction.getText(4, 158, 310, 485, 40), 6); + D2Bot.CDKeyInUse(); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + ControlAction.click(6, 335, 450, 128, 35); + ControlAction.timeoutDelay("LoD key in use", StarterConfig.CDKeyInUseDelay * 6e4); + } + + break; + default: + if (gameInfo.switchKeys) { + D2Bot.printToConsole("Invalid CD-Key"); + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + ControlAction.click(6, 335, 450, 128, 35); + ControlAction.timeoutDelay("Invalid CD-Key", StarterConfig.CDKeyInUseDelay * 6e4); + } + + break; + } + + break; + case 23: // Character Select - Connecting + case 42: // Empty character screen + if (!locationTimeout(StarterConfig.ConnectingTimeout * 1e3, location)) { + ControlAction.click(6, 33, 572, 128, 35); + } + + if (gameInfo.rdBlocker) { + D2Bot.restart(); + } + + break; + case 24: // Server Down - not much to do but wait.. + break; + case 25: // Lobby - Please Wait + if (!locationTimeout(StarterConfig.PleaseWaitTimeout * 1e3, location)) { + ControlAction.click(6, 351, 337, 96, 32); + } + + break; + case 26: // Lobby - Game Name Exists + ControlAction.click(6, 533, 469, 120, 20); + + gameCount += 1; + lastGameStatus = "ready"; + + break; + case 27: // Gateway Select + ControlAction.click(6, 436, 538, 96, 32); + + break; + case 28: // Lobby - Game Does Not Exist + D2Bot.printToConsole("Game doesn't exist"); + + if (gameInfo.rdBlocker) { + D2Bot.printToConsole(gameInfo.mpq + " is probably flagged.", 6); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } + } else { + locationTimeout(StarterConfig.GameDoesNotExistTimeout * 1e3, location); + } + + lastGameStatus = "ready"; + + break; + case 38: // Game is full + // doesn't happen when making + break; + default: + if (location !== undefined) { + D2Bot.printToConsole("Unhandled location " + location); + //takeScreenshot(); + delay(500); + D2Bot.restart(); + } + + break; + } +} \ No newline at end of file diff --git a/d2bs/kolbot/default.dbj b/d2bs/kolbot/default.dbj index 5afd39264..e9ce52af5 100644 --- a/d2bs/kolbot/default.dbj +++ b/d2bs/kolbot/default.dbj @@ -6,6 +6,7 @@ include("NTItemParser.dbl"); include("OOG.js"); include("AutoMule.js"); include("Gambling.js"); +include("CraftingSystem.js"); include("TorchSystem.js"); include("MuleLogger.js"); include("common/Attack.js"); @@ -54,7 +55,7 @@ function main() { return true; } - var i, sojPause, stats, + var i, sojPause, stats, anni, sojCounter = 0, startTime = getTickCount(); @@ -74,11 +75,28 @@ function main() { } }; + this.copyDataEvent = function (mode, msg) { + if (mode === 0 && msg === "mule") { // "Mule Profile" option from D2Bot# + if (AutoMule.getInfo() && AutoMule.getInfo().hasOwnProperty("muleInfo")) { + if (AutoMule.getMuleItems().length > 0) { + D2Bot.printToConsole("Mule triggered"); + scriptBroadcast("mule"); + scriptBroadcast("quit"); + } else { + D2Bot.printToConsole("No items to mule."); + } + } else { + D2Bot.printToConsole("Profile not enabled for muling."); + } + } + }; + // Initialize libs - load config variables, build pickit list, attacks, containers and cubing and runeword recipes Config.init(true); Pickit.init(true); Attack.init(); Storage.Init(); + CraftingSystem.buildLists(); Runewords.init(); Cubing.init(); @@ -97,6 +115,11 @@ function main() { return true; } + // Crafting System handler + if (CraftingSystem.inGameCheck()) { + return true; + } + me.maxgametime = Config.MaxGameTime * 1000; stats = DataFile.getStats(); @@ -112,6 +135,7 @@ function main() { // Load events and threads addEventListener("scriptmsg", this.scriptEvent); + addEventListener("copydata", this.copyDataEvent); load("tools/ToolsThread.js"); if (Config.TownCheck || Config.TownHP || Config.TownMP) { @@ -136,9 +160,11 @@ function main() { Town.getCorpse(); Town.clearBelt(); Town.clearInventory(); - Pickit.pickItems(); + //Pickit.pickItems(); } + me.automap = Config.AutoMap; + // Next game = drop keys if (TorchSystem.keyCheck()) { scriptBroadcast("torch"); @@ -165,6 +191,7 @@ function main() { if (sojPause) { try { Town.goToTown(); + Town.doChores(); me.maxgametime = 0; @@ -198,12 +225,22 @@ function main() { scriptBroadcast("mule"); } + // Anni handler. Mule Anni if it's in unlocked space and profile is set to mule torch/anni. + anni = me.findItem(603, 0, -1, 7); + + if (anni && !Storage.Inventory.IsLocked(anni, Config.Inventory) && AutoMule.getInfo() && AutoMule.getInfo().hasOwnProperty("torchMuleInfo")) { + scriptBroadcast("muleAnni"); + } + + if (CraftingSystem.checkFullSets()) { + scriptBroadcast("crafting"); + } + if (TorchSystem.keyCheck()) { scriptBroadcast("torch"); } scriptBroadcast("quit"); - //delay(5000); // Don't end default before other scripts - possible JS_IsRunning crash fix return true; } \ No newline at end of file diff --git a/d2bs/kolbot/libs/AutoMule.js b/d2bs/kolbot/libs/AutoMule.js index 0f9fc28b0..2519b3661 100644 --- a/d2bs/kolbot/libs/AutoMule.js +++ b/d2bs/kolbot/libs/AutoMule.js @@ -20,13 +20,23 @@ var AutoMule = { stopProfile: "", // Trigger muling at the end of a game if used space in stash and inventory is equal to or more than given percent. - // Both conditions need to be met in order to trigger muling. usedStashTrigger: 80, - usedInventoryTrigger: 80 + usedInventoryTrigger: 80, + + // Mule items that have been stashed at some point but are no longer in pickit. + muleOrphans: true } }, - TorchMules: { + /** Torch/Anni mules + - Torch is muled in OrgTorch script after finishing uber Tristram successfully or when starting OrgTorch script with a Torch already on the character. + - Anni is muled after successfully killing Diablo in Palace Cellar level 3 using Config.KillDclone option or KillDClone script. + If a profile is listed in Torch/Anni mule's enabledProfiles list, it will also do a check to mule Anni at the end of each game. + Anni that is in locked inventory slot will not be muled. + + * Each mule will hold either a Torch or an Anni, but not both. As soon as the current mule has either one, a new one will be created. + */ + TorchAnniMules: { "Mule1": { muleProfile: "", // The name of mule profile in d2bot#. It will be started and stopped when needed. accountPrefix: "", // Account prefix. Numbers added automatically when making accounts. @@ -51,7 +61,7 @@ var AutoMule = { inGame: false, check: false, - torchCheck: false, + torchAnniCheck: false, // *** Master functions *** getInfo: function () { @@ -71,15 +81,15 @@ var AutoMule = { } } - for (i in this.TorchMules) { - if (this.TorchMules.hasOwnProperty(i)) { - for (j = 0; j < this.TorchMules[i].enabledProfiles.length; j += 1) { - if (this.TorchMules[i].enabledProfiles[j].toLowerCase() === me.profile.toLowerCase()) { + for (i in this.TorchAnniMules) { + if (this.TorchAnniMules.hasOwnProperty(i)) { + for (j = 0; j < this.TorchAnniMules[i].enabledProfiles.length; j += 1) { + if (this.TorchAnniMules[i].enabledProfiles[j].toLowerCase() === me.profile.toLowerCase()) { if (!info) { info = {}; } - info.torchMuleInfo = this.TorchMules[i]; + info.torchMuleInfo = this.TorchAnniMules[i]; } } } @@ -112,7 +122,7 @@ var AutoMule = { return info.muleInfo; } - if (this.torchCheck && info.hasOwnProperty("torchMuleInfo")) { + if (this.torchAnniCheck && info.hasOwnProperty("torchMuleInfo")) { return info.torchMuleInfo; } } @@ -121,7 +131,7 @@ var AutoMule = { }, outOfGameCheck: function () { - if (!this.check && !this.torchCheck) { + if (!this.check && !this.torchAnniCheck) { return false; } @@ -143,12 +153,12 @@ var AutoMule = { } addEventListener("copydata", MuleCheckEvent); - D2Bot.printToConsole("Starting" + (this.torchCheck ? " torch " : " ") + "mule profile: " + muleObj.muleProfile, 7); + D2Bot.printToConsole("Starting " + (this.torchAnniCheck === 2 ? "anni" : this.torchAnniCheck === 1 ? "torch" : "") + " mule profile: " + muleObj.muleProfile, 7); MainLoop: while (true) { // If nothing received our copy data start the mule profile - if (!sendCopyData(null, muleObj.muleProfile, 10, JSON.stringify({profile: me.profile, mode: this.torchCheck ? 1 : 0}))) { + if (!sendCopyData(null, muleObj.muleProfile, 10, JSON.stringify({profile: me.profile, mode: this.torchAnniCheck || 0}))) { D2Bot.start(muleObj.muleProfile); } @@ -222,7 +232,7 @@ MainLoop: this.inGame = false; this.check = false; - this.torchCheck = false; + this.torchAnniCheck = false; // No response - stop mule profile if (failCount >= 60) { @@ -277,8 +287,12 @@ MainLoop: function MuleModeEvent(msg) { switch (msg) { + case "2": + AutoMule.torchAnniCheck = 2; + + break; case "1": - AutoMule.torchCheck = true; + AutoMule.torchAnniCheck = 1; break; case "0": @@ -293,7 +307,7 @@ MainLoop: scriptBroadcast("getMuleMode"); delay(500); - if (!this.check && !this.torchCheck) { + if (!this.check && !this.torchAnniCheck) { print("Error - Unable to determine mule mode"); quit(); @@ -312,14 +326,16 @@ MainLoop: sendCopyData(null, muleObj.muleProfile, 11, "begin"); - if (this.torchCheck) { + if (this.torchAnniCheck === 2) { + print("ÿc4AutoMuleÿc0: In anni mule game."); + D2Bot.updateStatus("AutoMule: In game."); + this.dropCharm(true); + } else if (this.torchAnniCheck === 1) { print("ÿc4AutoMuleÿc0: In torch mule game."); - D2Bot.printToConsole("AutoMule: Transfering torch.", 7); D2Bot.updateStatus("AutoMule: In game."); - this.dropTorch(); + this.dropCharm(false); } else { print("ÿc4AutoMuleÿc0: In mule game."); - D2Bot.printToConsole("AutoMule: Transfering items.", 7); D2Bot.updateStatus("AutoMule: In game."); this.dropStuff(); } @@ -334,6 +350,9 @@ MainLoop: if (getTickCount() - tick > timeout) { D2Bot.printToConsole("Mule didn't rejoin. Picking up items.", 9); + + Misc.useItemLog = false; // Don't log items picked back up in town. + Pickit.pickItems(); break; @@ -354,6 +373,7 @@ MainLoop: scriptBroadcast("exit"); } + delay(2000); quit(); //delay(10000); @@ -368,6 +388,12 @@ MainLoop: var i, items = this.getMuleItems(); + if (!items || items.length === 0) { + return false; + } + + D2Bot.printToConsole("AutoMule: Transfering items.", 7); + for (i = 0; i < items.length; i += 1) { items[i].drop(); } @@ -380,16 +406,27 @@ MainLoop: // get a list of items to mule getMuleItems: function () { - var items = [], - item = me.getItem(-1, 0); + var item, items, info; + + info = this.getInfo(); + + if (!info || !info.hasOwnProperty("muleInfo")) { + return false; + } + + item = me.getItem(-1, 0); + items = []; if (item) { do { - if (Town.ignoredItemTypes.indexOf(item.itemType) === -1 && Pickit.checkItem(item).result > 0 && item.classid !== 549 && - (item.location === 7 || (item.location === 3 && !Storage.Inventory.IsLocked(item, Config.Inventory))) && - [76, 77, 78].indexOf(item.itemType) === -1 && // don't drop potions - ((!TorchSystem.getFarmers() && !TorchSystem.isFarmer()) || [647, 648, 649].indexOf(item.classid) === -1) && - !this.cubingIngredient(item) && !this.runewordIngredient(item)) { + if (Town.ignoredItemTypes.indexOf(item.itemType) === -1 && + (Pickit.checkItem(item).result > 0 || (item.location === 7 && info.muleInfo.hasOwnProperty("muleOrphans") && info.muleInfo.muleOrphans)) && + item.classid !== 549 && // Don't drop Horadric Cube + (item.classid !== 603 || item.quality !== 7) && // Don't drop Annihilus + (item.classid !== 604 || item.quality !== 7) && // Don't drop Hellfire Torch + (item.location === 7 || (item.location === 3 && !Storage.Inventory.IsLocked(item, Config.Inventory))) && // Don't drop items in locked slots + ((!TorchSystem.getFarmers() && !TorchSystem.isFarmer()) || [647, 648, 649].indexOf(item.classid) === -1) && // Don't drop Keys if part of TorchSystem + !this.cubingIngredient(item) && !this.runewordIngredient(item) && !this.utilityIngredient(item)) { // Don't drop Runeword/Cubing/CraftingSystem ingredients items.push(copyUnit(item)); } } while (item.getNext()); @@ -398,6 +435,10 @@ MainLoop: return items; }, + utilityIngredient: function (item) { + return CraftingSystem.validGids.indexOf(item.gid) > -1; + }, + // check if an item is a cubing ingredient cubingIngredient: function (item) { var i; @@ -438,33 +479,49 @@ MainLoop: return false; }, - dropTorch: function () { + dropCharm: function (dropAnni) { if (!Town.openStash()) { return false; } - var item = me.getItem(getScript("AnniStarter.dbj") ? "cm1" : "cm2"); + var item; + + if (dropAnni) { + item = me.findItem(603, 0, -1, 7); + + if (item && !Storage.Inventory.IsLocked(item, Config.Inventory)) { + D2Bot.printToConsole("AutoMule: Transfering Anni.", 7); + item.drop(); + delay(1000); + me.cancel(); + + return true; + } + + return false; + } + + item = me.findItem(604, 0, -1, 7); if (item) { - do { - if (item.quality === 7) { - item.drop(); - delay(1000); - me.cancel(); + D2Bot.printToConsole("AutoMule: Transfering Torch.", 7); + item.drop(); + delay(1000); + me.cancel(); - return true; - } - } while (item.getNext()); + return true; } - return false; + me.cancel(); + + return true; }, // *** Mule functions *** getMaster: function (info) { var i, j, k, muleObj; - muleObj = info.mode === 1 ? this.TorchMules : this.Mules; + muleObj = info.mode === 1 ? this.TorchAnniMules : this.Mules; for (i in muleObj) { if (muleObj.hasOwnProperty(i)) { @@ -490,7 +547,7 @@ MainLoop: var i, mule; mode = mode || 0; - mule = mode === 1 ? this.TorchMules : this.Mules; + mule = mode > 0 ? this.TorchAnniMules : this.Mules; for (i in mule) { if (mule.hasOwnProperty(i)) { @@ -504,17 +561,17 @@ MainLoop: return false; }, - getMuleFilename: function (mode) { + getMuleFilename: function (mode, master) { var i, mule, jsonObj, jsonStr, file; mode = mode || 0; - mule = mode === 1 ? this.TorchMules : this.Mules; + mule = mode > 0 ? this.TorchAnniMules : this.Mules; // Iterate through mule object for (i in mule) { if (mule.hasOwnProperty(i)) { // Mule profile matches config - if (mule[i].muleProfile && mule[i].muleProfile.toLowerCase() === me.profile.toLowerCase()) { + if (mule[i].muleProfile && mule[i].muleProfile.toLowerCase() === me.profile.toLowerCase() && mule[i].enabledProfiles.indexOf(master) > -1) { file = mode === 0 ? "logs/AutoMule." + i + ".json" : "logs/TorchMule." + i + ".json"; // If file exists check for valid info diff --git a/d2bs/kolbot/libs/CraftingSystem.js b/d2bs/kolbot/libs/CraftingSystem.js new file mode 100644 index 000000000..274fb41c2 --- /dev/null +++ b/d2bs/kolbot/libs/CraftingSystem.js @@ -0,0 +1,516 @@ +/** +* @filename CraftingSystem.js +* @author kolton +* @desc Multi-profile crafting system +* +* @notes This system is experimental, there will be no support offered for it. +* If you can't get it to work, leave it be. +*/ + +var CraftingSystem = {}; + +CraftingSystem.Teams = { + "Team 1": { + // List of profiles that will collect ingredients + Collectors: [], + + // List of profiles that will craft/reroll items + Workers: [], + + // List of Worker game names (without the numbers) + CraftingGames: [], + + /* BaseItems - list of base item class ids + * Ingredients - list of recipe ingredients + * SetAmount - number of full sets to gather before transfering + * Type - the type of recipe. Available options: "crafting", "runewords", "cubing" + */ + Sets: [ + // LLD Crafting + + // Caster Belt set, char lvl 29 + // Light Belt classid 345, shopped at nightmare Elzix + // Sharkskin Belt classid 391, shopped at nightmare Elzix + //{BaseItems: [345, 391], Ingredients: [615, 643, 561], SetAmount: 2, Type: "crafting"}, + + // Runeword Making + + // Spirit Runeset + Hel + //{BaseItems: [29, 30, 31], Ingredients: [616, 618, 619, 620, 624], SetAmount: 2, Type: "runewords"}, + + // Misc. Cubing + + // Reroll rare Diadem + //{BaseItems: [421], Ingredients: [601, 601, 601], SetAmount: 1, Type: "cubing"} + ] + } +}; + +// ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## + +// Get the Crafting System information for current profile +CraftingSystem.getInfo = function () { + var i, j, info; + + for (i in CraftingSystem.Teams) { + if (CraftingSystem.Teams.hasOwnProperty(i)) { + for (j = 0; j < CraftingSystem.Teams[i].Collectors.length; j += 1) { + if (CraftingSystem.Teams[i].Collectors[j].toLowerCase() === me.profile.toLowerCase()) { + info = CraftingSystem.Teams[i]; + info.collector = true; + info.worker = false; + + return info; + } + } + + for (j = 0; j < CraftingSystem.Teams[i].Workers.length; j += 1) { + if (CraftingSystem.Teams[i].Workers[j].toLowerCase() === me.profile.toLowerCase()) { + info = CraftingSystem.Teams[i]; + info.collector = false; + info.worker = true; + + return info; + } + } + } + } + + return false; +}; + +// ################################################# +// # Item collector out of game specific functions # +// ################################################# + +CraftingSystem.check = false; +CraftingSystem.inGame = false; + +CraftingSystem.outOfGameCheck = function () { + if (!CraftingSystem.check) { + return false; + } + + var worker, + info = CraftingSystem.getInfo(); + + function scriptMsg(msg) { + var obj; + + try { + obj = JSON.parse(msg); + } catch (e) { + return false; + } + + if (obj.name === "RequestWorker") { + scriptBroadcast(JSON.stringify({name: "WorkerName", value: worker.name})); + } + + return true; + } + + if (info && info.collector) { + worker = CraftingSystem.getWorker(); + + if (worker && worker.game) { + D2Bot.printToConsole("CraftingSystem: Transfering items.", 7); + D2Bot.updateStatus("CraftingSystem: In game."); + addEventListener("scriptmsg", scriptMsg); + + CraftingSystem.inGame = true; + me.blockMouse = true; + + delay(2000); + joinGame(worker.game[0], worker.game[1]); + + me.blockMouse = false; + + delay(5000); + + while (me.ingame) { + delay(1000); + } + + CraftingSystem.inGame = false; + CraftingSystem.check = false; + + removeEventListener("scriptmsg", scriptMsg); + + return true; + } + } + + return false; +}; + +CraftingSystem.getWorker = function () { + var i, + rval = { + game: false, + name: false + }, + info = CraftingSystem.getInfo(); + + function CheckEvent(mode, msg) { + var i; + + if (mode === 4) { + for (i = 0; i < info.CraftingGames.length; i += 1) { + if (info.CraftingGames[i] && msg.match(info.CraftingGames[i], "i")) { + rval.game = msg.split('/'); + + break; + } + } + } + } + + if (info && info.collector) { + addEventListener('copydata', CheckEvent); + + rval.game = false; + + for (i = 0; i < info.Workers.length; i += 1) { + sendCopyData(null, info.Workers[i], 0, JSON.stringify({name: "GetGame", profile: me.profile})); + delay(100); + + if (rval.game) { + rval.name = info.Workers[i]; + + break; + } + } + + removeEventListener('copydata', CheckEvent); + + return rval; + } + + return false; +}; + +// ############################################# +// # Item collector in-game specific functions # +// ############################################# + +CraftingSystem.inGameCheck = function () { + var i, + info = CraftingSystem.getInfo(); + + if (info && info.collector) { + for (i = 0; i < info.CraftingGames.length; i += 1) { + if (info.CraftingGames[i] && me.gamename.match(info.CraftingGames[i], "i")) { + CraftingSystem.dropItems(); + me.cancel(); + delay(5000); + quit(); + + return true; + } + } + } + + return false; +}; + +CraftingSystem.neededItems = []; +CraftingSystem.validGids = []; +CraftingSystem.itemList = []; +CraftingSystem.fullSets = []; + +// Check whether item can be used for crafting +CraftingSystem.validItem = function (item) { + switch (item.itemType) { + case 58: // Jewel + return NTIP.CheckItem(item) === 0; // Use junk jewels only + } + + return true; +}; + +// Check if the item should be picked for crafting +CraftingSystem.checkItem = function (item) { + var i, + info = CraftingSystem.getInfo(); + + if (info) { + for (i = 0; i < CraftingSystem.neededItems.length; i += 1) { + if (item.classid === CraftingSystem.neededItems[i] && CraftingSystem.validItem(item)) { + return true; + } + } + } + + return false; +}; + +// Check if the item should be kept or dropped +CraftingSystem.keepItem = function (item) { + var info = CraftingSystem.getInfo(); + + if (info) { + if (info.collector) { + return CraftingSystem.validGids.indexOf(item.gid) > -1; + } + + if (info.worker) { + if (item.quality === 8) { // Let pickit decide whether to keep crafted + return false; + } + + return true; + } + } + + return false; +}; + +// Collect ingredients only if a worker needs them +CraftingSystem.getSetInfoFromWorker = function (workerName) { + var setInfo = false, + info = CraftingSystem.getInfo(); + + function copyData(mode, msg) { + var obj; + + if (mode === 4) { + try { + obj = JSON.parse(msg); + } catch (e) { + return false; + } + + if (obj && obj.name === "SetInfo") { + setInfo = obj.value; + } + } + + return true; + } + + if (info && info.collector) { + addEventListener("copydata", copyData); + sendCopyData(null, workerName, 0, JSON.stringify({name: "GetSetInfo", profile: me.profile})); + delay(100); + + if (setInfo !== false) { + removeEventListener("copydata", copyData); + + return setInfo; + } + + removeEventListener("copydata", copyData); + } + + return false; +}; + +CraftingSystem.init = function (name) { + var i, setInfo, + info = CraftingSystem.getInfo(); + + if (info && info.collector) { + for (i = 0; i < info.Sets.length; i += 1) { + info.Sets[i].Enabled = false; + } + + setInfo = CraftingSystem.getSetInfoFromWorker(name); + + if (setInfo) { + for (i = 0; i < setInfo.length; i += 1) { + if (setInfo[i] === 1 && info.Sets[i].Enabled === false) { + info.Sets[i].Enabled = true; + } + } + } + } +}; + +// Build global lists of needed items and valid ingredients +CraftingSystem.buildLists = function (onlyNeeded) { + var i, + info = CraftingSystem.getInfo(); + + if (info && info.collector) { + CraftingSystem.neededItems = []; + CraftingSystem.validGids = []; + CraftingSystem.fullSets = []; + CraftingSystem.itemList = me.findItems(-1, 0); + + for (i = 0; i < info.Sets.length; i += 1) { + if (!onlyNeeded || info.Sets[i].Enabled) { + CraftingSystem.checkSet(info.Sets[i]); + } + } + + return true; + } + + return false; +}; + +// Check which ingredients a set needs and has +CraftingSystem.checkSet = function (set) { + var i, j, amount, + rval = {}, + setNeeds = [], + setHas = []; + + // Get what set needs + for (amount = 0; amount < set.SetAmount; amount += 1) { // Multiply by SetAmount + for (i = 0; i < set.Ingredients.length; i += 1) { + setNeeds.push(set.Ingredients[i]); + } + } + + // Remove what set already has + for (i = 0; i < setNeeds.length; i += 1) { + for (j = 0; j < CraftingSystem.itemList.length; j += 1) { + if (CraftingSystem.itemList[j].classid === setNeeds[i]) { + setHas.push(CraftingSystem.itemList[j].gid); + setNeeds.splice(i, 1); + CraftingSystem.itemList.splice(j, 1); + + i -= 1; + j -= 1; + } + } + } + + // The set is complete + if (setNeeds.length === 0) { + CraftingSystem.fullSets.push(setHas.slice()); + } + + CraftingSystem.neededItems = CraftingSystem.neededItems.concat(setNeeds); + CraftingSystem.validGids = CraftingSystem.validGids.concat(setHas); + + CraftingSystem.neededItems.sort(Sort.numbers); + CraftingSystem.validGids.sort(Sort.numbers); + + return rval; +}; + +// Update lists when a valid ingredient is picked +CraftingSystem.update = function (item) { + CraftingSystem.neededItems.splice(CraftingSystem.neededItems.indexOf(item.classid), 1); + CraftingSystem.validGids.push(item.gid); + + return true; +}; + +// Cube flawless gems if the ingredient is a perfect gem +CraftingSystem.checkSubrecipes = function () { + var i; + + for (i = 0; i < CraftingSystem.neededItems.length; i += 1) { + switch (CraftingSystem.neededItems[i]) { + case 561: // Pgems + case 566: + case 571: + case 576: + case 581: + case 586: + case 601: + if (Cubing.subRecipes.indexOf(CraftingSystem.neededItems[i]) === -1) { + Cubing.subRecipes.push(CraftingSystem.neededItems[i]); + Cubing.recipes.push({ + Ingredients: [CraftingSystem.neededItems[i] - 1, CraftingSystem.neededItems[i] - 1, CraftingSystem.neededItems[i] - 1], + Index: 0, + AlwaysEnabled: true, + MainRecipe: "Crafting" + }); + } + + break; + } + } + + return true; +}; + +// Check if there are any complete ingredient sets +CraftingSystem.checkFullSets = function () { + var i, + info = CraftingSystem.getInfo(); + + if (info && info.collector) { + for (i = 0; i < info.Workers.length; i += 1) { + CraftingSystem.init(info.Workers[i]); + CraftingSystem.buildLists(true); + + if (CraftingSystem.fullSets.length) { + return true; + } + } + } + + return false; +}; + +// Drop complete ingredient sets +CraftingSystem.dropItems = function () { + Town.goToTown(1); + Town.move("stash"); + Town.openStash(); + + var gidList, item, worker; + + function scriptMsg(msg) { + var obj; + + try { + obj = JSON.parse(msg); + } catch (e) { + return false; + } + + if (obj.name === "WorkerName") { + worker = obj.value; + } + + return true; + } + + addEventListener("scriptmsg", scriptMsg); + scriptBroadcast(JSON.stringify({name: "RequestWorker"})); + delay(100); + + if (worker) { + CraftingSystem.init(worker); + CraftingSystem.buildLists(true); + removeEventListener("scriptmsg", scriptMsg); + + while (CraftingSystem.fullSets.length) { + gidList = CraftingSystem.fullSets.shift(); + + while (gidList.length) { + item = me.getItem(-1, -1, gidList.shift()); + + if (item) { + item.drop(); + } + } + } + + CraftingSystem.dropGold(); + delay(1000); + me.cancel(); + } + + return true; +}; + +CraftingSystem.dropGold = function () { + Town.goToTown(1); + Town.move("stash"); + + if (me.getStat(14) >= 10000) { + gold(10000); + } else if (me.getStat(15) + me.getStat(14) >= 10000) { + Town.openStash(); + gold(10000 - me.getStat(14), 4); + gold(10000); + } +}; \ No newline at end of file diff --git a/d2bs/kolbot/libs/MuleLogger.js b/d2bs/kolbot/libs/MuleLogger.js index c98653ad1..eb4f137b3 100644 --- a/d2bs/kolbot/libs/MuleLogger.js +++ b/d2bs/kolbot/libs/MuleLogger.js @@ -30,10 +30,14 @@ var MuleLogger = { IngameTime: 20, // Time to wait after leaving game // don't edit - getItemDesc: function (unit) { + getItemDesc: function (unit, logIlvl) { var i, desc, stringColor = ""; + if (logIlvl === undefined) { + logIlvl = this.LogItemLevel; + } + desc = unit.description.split("\n"); // Lines are normally in reverse. Add color tags if needed and reverse order. @@ -53,7 +57,7 @@ var MuleLogger = { desc[i] = desc[i].replace(/(y|ÿ)c([0-9!"+<;.*])/g, "\\xffc$2").replace("\xFF", "\\xff", "g"); } - if (this.LogItemLevel && desc[desc.length - 1]) { + if (logIlvl && desc[desc.length - 1]) { desc[desc.length - 1] = desc[desc.length - 1].trim() + " (" + unit.ilvl + ")"; } @@ -82,17 +86,21 @@ var MuleLogger = { }, // Log kept item stats in the manager. - logItem: function (unit) { - /*if (!isIncluded("common/misc.js")) { + logItem: function (unit, logIlvl) { + if (!isIncluded("common/misc.js")) { include("common/misc.js"); - }*/ + } + + if (logIlvl === undefined) { + logIlvl = this.LogItemLevel; + } var i, code, desc, sock, header = "", color = -1, - name = unit.fname.split("\n").reverse().join(" ").replace(/(y|ÿ)c[0-9!"+<;.*]/, "").trim(); + name = unit.itemType + "_" + unit.fname.split("\n").reverse().join(" ").replace(/(y|ÿ)c[0-9!"+<;.*]/, "").trim(); - desc = this.getItemDesc(unit) + "$" + unit.gid; + desc = this.getItemDesc(unit, logIlvl) + "$" + unit.gid; color = unit.getColor(); switch (unit.quality) { @@ -248,23 +256,31 @@ var MuleLogger = { } } - if (this.LogNames) { - header = (me.account || "Single Player") + " / " + me.name; - } - return { itemColor: color, image: code, title: name, description: desc, header: header, - sockets: Misc.getItemSockets(unit) // not yet implemented + sockets: Misc.getItemSockets(unit) }; }, - logChar: function () { + logChar: function (logIlvl, logName, saveImg) { while (!me.gameReady) { - delay(500); + delay(100); + } + + if (logIlvl === undefined) { + logIlvl = this.LogItemLevel; + } + + if (logName === undefined) { + logName = this.LogNames; + } + + if (saveImg === undefined) { + saveImg = this.SaveScreenShot; } var i, folder, string, parsedItem, @@ -289,9 +305,32 @@ var MuleLogger = { return; } + function itemSort(a, b) { + return b.itemType - a.itemType; + } + + items.sort(itemSort); + for (i = 0; i < items.length; i += 1) { if (this.LogEquipped || (!this.LogEquipped && items[i].mode === 0)) { - parsedItem = this.logItem(items[i]); + parsedItem = this.logItem(items[i], logIlvl); + + // Log names to saved image + if (logName) { + parsedItem.header = (me.account || "Single Player") + " / " + me.name; + } + + if (saveImg) { + D2Bot.saveItem(parsedItem); + } + + // Always put name on Char Viewer items + if (!parsedItem.header) { + parsedItem.header = (me.account || "Single Player") + " / " + me.name; + } + + // Remove itemtype_ prefix from the name + parsedItem.title = parsedItem.title.substr(parsedItem.title.indexOf("_") + 1); if (items[i].mode === 1) { parsedItem.title += " (equipped)"; @@ -299,28 +338,26 @@ var MuleLogger = { string = JSON.stringify(parsedItem); finalString += (string + "\n"); - - if (this.SaveScreenShot) { - D2Bot.saveItem(parsedItem); - } } } if (this.LogMerc) { for (i = 0; i < 3; i += 1) { merc = me.getMerc(); + if (merc) { break; } + delay(50); } - + if (merc) { items = merc.getItems(); + for (i = 0; i < items.length; i += 1) { parsedItem = this.logItem(items[i]); parsedItem.title += " (merc)"; - string = JSON.stringify(parsedItem); finalString += (string + "\n"); @@ -330,7 +367,8 @@ var MuleLogger = { } } } + FileTools.writeText("mules/" + realm + "/" + me.account + "/" + me.name + ".txt", finalString); print("Item logging done."); } -}; +}; \ No newline at end of file diff --git a/d2bs/kolbot/libs/NTItemAlias.dbl b/d2bs/kolbot/libs/NTItemAlias.dbl index bef462d96..e9e4a470a 100644 --- a/d2bs/kolbot/libs/NTItemAlias.dbl +++ b/d2bs/kolbot/libs/NTItemAlias.dbl @@ -1,4 +1,4 @@ -var NTIPAliasType = {}; +var NTIPAliasType = {}; NTIPAliasType["shield"] = 2; NTIPAliasType["armor"] = 3; NTIPAliasType["gold"] = 4; @@ -101,7 +101,7 @@ NTIPAliasType["sapphire"] = 100; NTIPAliasType["topaz"] = 101; NTIPAliasType["skull"] = 102; -var NTIPAliasClassID = {}; +var NTIPAliasClassID = {}; NTIPAliasClassID["hax"] = 0; NTIPAliasClassID["handaxe"] = 0; NTIPAliasClassID["axe"] = 1; NTIPAliasClassID["2ax"] = 2; NTIPAliasClassID["doubleaxe"] = 2; @@ -762,12 +762,12 @@ NTIPAliasClassID["bet"] = 656; NTIPAliasClassID["burningessenceofterror"] = 656 NTIPAliasClassID["fed"] = 657; NTIPAliasClassID["festeringessenceofdestruction"] = 657; NTIPAliasClassID["std"] = 658; NTIPAliasClassID["standardofheroes"] = 658; -var NTIPAliasClass = {}; +var NTIPAliasClass = {}; NTIPAliasClass["normal"] = 0; NTIPAliasClass["exceptional"] = 1; NTIPAliasClass["elite"] = 2; -var NTIPAliasQuality = {}; +var NTIPAliasQuality = {}; NTIPAliasQuality["lowquality"] = 1; NTIPAliasQuality["normal"] = 2; NTIPAliasQuality["superior"] = 3; @@ -777,31 +777,31 @@ NTIPAliasQuality["rare"] = 6; NTIPAliasQuality["unique"] = 7; NTIPAliasQuality["crafted"] = 8; -var NTIPAliasFlag = {}; +var NTIPAliasFlag = {}; NTIPAliasFlag["identified"] = 0x10; NTIPAliasFlag["eth"] = 0x400000; NTIPAliasFlag["ethereal"] = 0x400000; NTIPAliasFlag["runeword"] = 0x4000000; // rare item colors -var NTIPAliasColor = {}; -NTIPAliasColor["black"] = 3; -NTIPAliasColor["white"] = 20; -NTIPAliasColor["orange"] = 19; -NTIPAliasColor["lightyellow"] = 13; -NTIPAliasColor["lightred"] = 7; -NTIPAliasColor["lightgold"] = 15; -NTIPAliasColor["lightblue"] = 4; -NTIPAliasColor["lightpurple"] = 17; -NTIPAliasColor["crystalblue"] = 6; -NTIPAliasColor["crystalred"] = 9; -NTIPAliasColor["crystalgreen"] = 12; -NTIPAliasColor["darkyellow"] = 14; -NTIPAliasColor["darkred"] = 8; -NTIPAliasColor["darkgold"] = 16; -NTIPAliasColor["darkgreen"] = 11; -NTIPAliasColor["darkblue"] = 5; +var NTIPAliasColor = {}; +NTIPAliasColor["black"] = 3; +NTIPAliasColor["white"] = 20; +NTIPAliasColor["orange"] = 19; +NTIPAliasColor["lightyellow"] = 13; +NTIPAliasColor["lightred"] = 7; +NTIPAliasColor["lightgold"] = 15; +NTIPAliasColor["lightblue"] = 4; +NTIPAliasColor["lightpurple"] = 17; +NTIPAliasColor["crystalblue"] = 6; +NTIPAliasColor["crystalred"] = 9; +NTIPAliasColor["crystalgreen"] = 12; +NTIPAliasColor["darkyellow"] = 14; +NTIPAliasColor["darkred"] = 8; +NTIPAliasColor["darkgold"] = 16; +NTIPAliasColor["darkgreen"] = 11; +NTIPAliasColor["darkblue"] = 5; -var NTIPAliasStat = {}; +var NTIPAliasStat = {}; NTIPAliasStat["strength"] = 0; NTIPAliasStat["energy"] = 1; NTIPAliasStat["dexterity"] = 2; @@ -864,6 +864,7 @@ NTIPAliasStat["magicmaxdam"] = 53; NTIPAliasStat["coldmindam"] = 54; NTIPAliasStat["coldmaxdam"] = 55; NTIPAliasStat["coldlength"] = 56; +NTIPAliasStat["poisondamage"] = [57, 1]; NTIPAliasStat["poisonmindam"] = 57; NTIPAliasStat["poisonmaxdam"] = 58; NTIPAliasStat["poisonlength"] = 59; @@ -917,6 +918,7 @@ NTIPAliasStat["itemfastermovevelocity"] = 96; NTIPAliasStat["frw"] = 96; // oskill NTIPAliasStat["itemnonclassskill"] = 97; // Amazon +NTIPAliasStat["plusskillcriticalstrike"] = [97,9]; NTIPAliasStat["plusskillguidedarrow"] = [97,22]; // Sorceress NTIPAliasStat["plusskillteleport"] = [97,54]; diff --git a/d2bs/kolbot/libs/NTItemParser.dbl b/d2bs/kolbot/libs/NTItemParser.dbl index 1d75ac2b6..fffaaf9de 100644 --- a/d2bs/kolbot/libs/NTItemParser.dbl +++ b/d2bs/kolbot/libs/NTItemParser.dbl @@ -35,18 +35,9 @@ NTIP.OpenFile = function (filepath, notify) { var i, nipfile, line, lines, info, item, tick = getTickCount(), - //hash = md5_file(filepath), filename = filepath.substring(filepath.lastIndexOf("/") + 1, filepath.length), entries = 0; - /*if (!FileTools.exists("pickit/minified/" + hash + "." + filename)) { - NTIP.Minify(filepath); - } - - if (FileTools.exists("pickit/minified/" + hash + "." + filename)) { - filepath = "pickit/minified/" + hash + "." + filename; - }*/ - try { nipfile = File.open(filepath, 0); } catch (fileError) { @@ -60,28 +51,6 @@ NTIP.OpenFile = function (filepath, notify) { } lines = nipfile.readAllLines(); - /*item = { - itemType: 0, - classid: 0, - itemclass: 0, - quality: 0, - ilvl: 0, - getFlag: function () { - return false; - }, - getColor: function () { - return false; - }, - getPrefix: function () { - return false; - }, - getSuffix: function () { - return false; - }, - getStatEx: function () { - return false; - } - };*/ nipfile.close(); @@ -94,28 +63,6 @@ NTIP.OpenFile = function (filepath, notify) { line = NTIP.ParseLineInt(lines[i], info); - // frickaline try/catch method - // switching to this would mean adding a separate check for runeword entries - /*if (line) { - try { - if (line[0] && line[0].length) { - eval(line[0]); - } - - if (line[1] && line[1].length) { - eval(line[1]); - } - - if (line[2] && line[2].length) { - eval(line[2]); - } - } catch (lineError) { - Misc.errorReport("Bad Line: " + lines[i]); - - line = false; - } - }*/ - if (line) { entries += 1; @@ -192,9 +139,9 @@ NTIP.CheckQuantityOwned = function (item_type, item_stats) { if ((item_type !== null && item_type.length > 0 && eval(item_type)) || item_type === null) { if ((item_stats !== null && item_stats.length > 0 && eval(item_stats)) || item_stats === null) { - if (Config.Inventory[items[i].y][items[i].x] > 0) { // we check only space that is supposed to be free + //if (Config.Inventory[items[i].y][items[i].x] > 0) { // we check only space that is supposed to be free num += 1; - } + //} } } } @@ -210,8 +157,47 @@ NTIP.Clear = function () { stringArray = []; }; +NTIP.GetTier = function (item) { + var i, + tier = 0; + + // Go through ALL lines that describe the item + for (i = 0; i < NTIP_CheckList.length; i += 1) { + if (NTIP_CheckList[i].length === 3 && NTIP_CheckList[i][2].hasOwnProperty("Tier") && !isNaN(NTIP_CheckList[i][2].Tier)) { + try { + if (NTIP_CheckList[i][0].length > 0) { + if (eval(NTIP_CheckList[i][0])) { + if (NTIP_CheckList[i][1].length > 0) { + if (eval(NTIP_CheckList[i][1])) { + if (NTIP_CheckList[i][2].Tier > tier) { + tier = NTIP_CheckList[i][2].Tier; + } + } + } else { + if (NTIP_CheckList[i][2].Tier > tier) { + tier = NTIP_CheckList[i][2].Tier; + } + } + } + } else if (NTIP_CheckList[i][1].length > 0) { + if (eval(NTIP_CheckList[i][1])) { + if (NTIP_CheckList[i][2].Tier > tier) { + tier = NTIP_CheckList[i][2].Tier; + } + } + } + } catch (e) { + + } + } + } + + return tier; +}; + NTIP.CheckItem = function (item, entryList, verbose) { - var i, list, identified, num, tier, rval, + var i, list, identified, num, + rval = {}, result = 0; if (!entryList) { @@ -228,10 +214,6 @@ NTIP.CheckItem = function (item, entryList, verbose) { if (eval(list[i][0])) { if (list[i][1].length > 0) { if (eval(list[i][1])) { - if (list[i][2] && list[i][2].Tier && !isNaN(list[i][2].Tier)) { - tier = list[i][2].Tier; - } - if (list[i][2] && list[i][2].MaxQuantity && !isNaN(list[i][2].MaxQuantity)) { num = NTIP.CheckQuantityOwned(list[i][0], list[i][1]); @@ -253,12 +235,12 @@ NTIP.CheckItem = function (item, entryList, verbose) { } } else if (!identified && result === 0) { result = -1; + + if (verbose) { + rval.line = stringArray[i].file + " #" + stringArray[i].line; + } } } else { - if (list[i][2] && list[i][2].Tier && !isNaN(list[i][2].Tier)) { - tier = list[i][2].Tier; - } - if (list[i][2] && list[i][2].MaxQuantity && !isNaN(list[i][2].MaxQuantity)) { num = NTIP.CheckQuantityOwned(list[i][0], null); @@ -282,10 +264,6 @@ NTIP.CheckItem = function (item, entryList, verbose) { } } else if (list[i][1].length > 0) { if (eval(list[i][1])) { - if (list[i][2] && list[i][2].Tier && !isNaN(list[i][2].Tier)) { - tier = list[i][2].Tier; - } - if (list[i][2] && list[i][2].MaxQuantity && !isNaN(list[i][2].MaxQuantity)) { num = NTIP.CheckQuantityOwned(null, list[i][1]); @@ -307,13 +285,17 @@ NTIP.CheckItem = function (item, entryList, verbose) { } } else if (!identified && result === 0) { result = -1; + + if (verbose) { + rval.line = stringArray[i].file + " #" + stringArray[i].line; + } } } } catch (pickError) { showConsole(); if (!entryList) { - Misc.errorReport("ÿc1Pickit error! Line # ÿc2" + stringArray[i].line + " ÿc1Entry: ÿc0" + stringArray[i].string + " (" + stringArray[i].file + ")"); + Misc.errorReport("ÿc1Pickit error! Line # ÿc2" + stringArray[i].line + " ÿc1Entry: ÿc0" + stringArray[i].string + " (" + stringArray[i].file + ") Error message: " + pickError.message + " Trigger item: " + item.fname.split("\n").reverse().join(" ")); NTIP_CheckList[i] = ["", "", ""]; // make the bad entry blank } else { @@ -325,16 +307,20 @@ NTIP.CheckItem = function (item, entryList, verbose) { } if (verbose) { - rval = {}; - - if (result > 0) { + switch (result) { + case -1: + break; + case 1: rval.line = stringArray[i].file + " #" + stringArray[i].line; - } else { + + break; + default: rval.line = null; + + break; } rval.result = result; - rval.tier = tier; return rval; } @@ -441,6 +427,12 @@ NTIP.ParseLineInt = function (input, info) { p_result[0] += p_section[i].substring(p_start, p_end); + if (p_section[i].substring(p_start, p_end) === "=") { + Misc.errorReport("Unexpected = at line " + info.line + " in " + info.file); + + return false; + } + for (p_start = p_end; p_end < p_section[i].length; p_end += 1) { if (NTIP.IsSyntaxInt(p_section[i][p_end])) { break; @@ -557,7 +549,7 @@ NTIP.ParseLineInt = function (input, info) { p_result[1] = ""; } - if (p_result[2] && p_result[2].replace(/^\s+|\s+$/, "").length > 0) { + if (p_result[2] && p_result[2].length > 0) { p_section = p_result[2].split("["); p_result[2] = {}; @@ -565,31 +557,25 @@ NTIP.ParseLineInt = function (input, info) { p_end = p_section[i].indexOf("]"); p_keyword = p_section[i].substring(0, p_end); - switch (p_keyword.toLowerCase().replace(/^\s+|\s+$/, "")) { + switch (p_keyword.toLowerCase()) { case "maxquantity": - p_end = p_section[i].split("==")[1].replace(/^\s+|\s+$/, "").indexOf("//"); + value = Number(p_section[i].split("==")[1].match(/\d+/g)); - if (p_end === -1) { - p_end = p_section[i].split("==")[1].replace(/^\s+|\s+$/, "").length; + if (!isNaN(value)) { + p_result[2].MaxQuantity = value; } - value = Number(p_section[i].split("==")[1].replace(/^\s+|\s+$/, "").substring(0, p_end)); - p_result[2].MaxQuantity = value; - break; case "tier": - p_end = p_section[i].split("==")[1].replace(/^\s+|\s+$/, "").indexOf("//"); + value = Number(p_section[i].split("==")[1].match(/\d+/g)); - if (p_end === -1) { - p_end = p_section[i].split("==")[1].replace(/^\s+|\s+$/, "").length; + if (!isNaN(value)) { + p_result[2].Tier = value; } - value = Number(p_section[i].split("==")[1].replace(/^\s+|\s+$/, "").substring(0, p_end)); - p_result[2].Tier = value; - break; default: - Misc.errorReport("Unknown 3rd part keyword: " + p_keyword.toLowerCase().replace(/^\s+|\s+$/, "")); + Misc.errorReport("Unknown 3rd part keyword: " + p_keyword.toLowerCase()); return false; } diff --git a/d2bs/kolbot/libs/OOG.js b/d2bs/kolbot/libs/OOG.js index f5c015b21..170f7f63c 100644 --- a/d2bs/kolbot/libs/OOG.js +++ b/d2bs/kolbot/libs/OOG.js @@ -48,6 +48,56 @@ var D2Bot = { sendCopyData(null, this.handle, 0, JSON.stringify(obj)); }, + uploadItem: function (itemObj) { + var obj = { + profile: me.profile, + func: "uploadItem", + args: [JSON.stringify(itemObj)] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); + }, + + writeToFile: function (filename, msg) { + var obj = { + profile: me.profile, + func: "writeToFile", + args: [filename, msg] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); + }, + + postToIRC: function (ircProfile, recepient, msg) { + var obj = { + profile: me.profile, + func: "postToIRC", + args: [ircProfile, recepient, msg] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); + }, + + ircEvent: function (mode) { + var obj = { + profile: me.profile, + func: "ircEvent", + args: [mode ? "true" : "false"] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); + }, + + notify: function (msg) { + var obj = { + profile: me.profile, + func: "notify", + args: [msg] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); + }, + saveItem: function (itemObj) { var obj = { profile: me.profile, @@ -148,15 +198,19 @@ var D2Bot = { sendCopyData(null, this.handle, 0, JSON.stringify(obj)); }, - stop: function (profile) { + stop: function (profile, release) { if (!profile) { profile = me.profile; } + if (release === undefined) { + release = false; + } + var obj = { profile: me.profile, func: "stop", - args: [profile] + args: [profile, release] }; sendCopyData(null, this.handle, 0, JSON.stringify(obj)); @@ -172,6 +226,26 @@ var D2Bot = { sendCopyData(null, this.handle, 0, JSON.stringify(obj)); }, + startSchedule: function (profile) { + var obj = { + profile: me.profile, + func: "startSchedule", + args: [profile] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); + }, + + stopSchedule: function (profile) { + var obj = { + profile: me.profile, + func: "stopSchedule", + args: [profile] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); + }, + updateCount: function () { var obj = { profile: me.profile, @@ -329,7 +403,7 @@ var DataFile = { getStats: function () { var obj = this.getObj(); - return {runs: obj.runs, experience: obj.experience, lastArea: obj.lastArea, gold: obj.gold, level: obj.level, name: obj.name, gameName: obj.gameName, ingameTick: obj.ingameTick, handle: obj.handle, nextGame: obj.nextGame}; + return Misc.clone(obj); }, updateStats: function (arg, value) { @@ -352,10 +426,6 @@ var DataFile = { for (i = 0; i < statArr.length; i += 1) { switch (statArr[i]) { - case "runs": - obj.runs = value; - - break; case "experience": obj.experience = me.getStat(13); obj.level = me.getStat(12); @@ -370,16 +440,16 @@ var DataFile = { break; case "gold": + if (!me.gameReady) { + break; + } + obj.gold = me.getStat(14) + me.getStat(15); break; case "name": obj.name = me.name; - break; - case "gameName": - obj.gameName = value; - break; case "ingameTick": obj.ingameTick = getTickCount(); @@ -389,12 +459,8 @@ var DataFile = { obj.deaths = (obj.deaths || 0) + 1; break; - case "handle": - obj.handle = value; - - break; - case "nextGame": - obj.nextGame = value; + default: + obj[statArr[i]] = value; break; } @@ -411,15 +477,21 @@ var ControlAction = { mutedKey: false, timeoutDelay: function (text, time, stopfunc, arg) { - var endTime = getTickCount() + time; + var currTime = 0, + endTime = getTickCount() + time; while (getTickCount() < endTime) { if (typeof stopfunc === "function" && stopfunc(arg)) { break; } - D2Bot.updateStatus(text + " (" + Math.floor((endTime - getTickCount()) / 1000) + "s)"); - delay(500); + if (currTime !== Math.floor((endTime - getTickCount()) / 1000)) { + currTime = Math.floor((endTime - getTickCount()) / 1000); + + D2Bot.updateStatus(text + " (" + Math.max(currTime, 0) + "s)"); + } + + delay(10); } }, @@ -442,14 +514,26 @@ var ControlAction = { return false; } - var control = getControl(type, x, y, xsize, ysize); + var currText, + control = getControl(type, x, y, xsize, ysize); if (!control) { return false; } - //delay(textdelay); - delay(200); + currText = control.text; + + if (currText && currText === text) { + return true; + } + + currText = control.getText(); + + if (currText && ((typeof currText === "string" && currText === text) || (typeof currText === "object" && currText.indexOf(text) > -1))) { + return true; + } + + //delay(200); control.setText(text); return true; @@ -519,6 +603,8 @@ MainLoop: }, createGame: function (name, pass, diff, delay) { + var control; + ControlAction.setText(1, 432, 162, 158, 20, name); ControlAction.setText(1, 432, 217, 158, 20, pass); @@ -530,9 +616,29 @@ MainLoop: case "Nightmare": ControlAction.click(6, 555, 381, 16, 16); + break; + case "Highest": + control = getControl(6, 698, 381, 16, 16); + + if (control.disabled !== 4) { + ControlAction.click(6, 698, 381, 16, 16); // Click Hell + + break; + } + + control = getControl(6, 555, 381, 16, 16); + + if (control.disabled !== 4) { + ControlAction.click(6, 555, 381, 16, 16); // Click Nightmare + + break; + } + + ControlAction.click(6, 430, 381, 16, 16); // Click Normal + break; default: - ControlAction.click(6, 698, 381, 16, 16); + ControlAction.click(6, 698, 381, 16, 16); // Click Hell break; } @@ -623,6 +729,8 @@ MainLoop: MainLoop: while (true) { switch (getLocation()) { + case 0: + break; case 8: // main menu if (info.realm) { ControlAction.clickRealm(realms[info.realm]); @@ -657,7 +765,7 @@ MainLoop: // make sure we're not on connecting screen locTick = getTickCount(); - while (getTickCount() - locTick < 2000 && getLocation() === 42) { + while (getTickCount() - locTick < 3000 && getLocation() === 42) { delay(25); } @@ -682,7 +790,7 @@ MainLoop: delay(100); } - //delay(1000); + delay(1000); me.blockMouse = false; @@ -855,6 +963,11 @@ MainLoop: this.click(6, 33, 572, 128, 35); break; + case 14: // disconnected? + case 30: // player not found? + me.blockMouse = false; + + return false; default: break; } @@ -874,12 +987,21 @@ MainLoop: info.charClass = "barbarian"; } - var clickCoords = []; + var control, + clickCoords = []; while (getLocation() !== 1) { // cycle until in lobby switch (getLocation()) { case 12: // character select case 42: // empty character select + control = getControl(6, 33, 528, 168, 60); + + if (control && control.disabled === 4) { // Create Character greyed out + me.blockMouse = false; + + return false; + } + this.click(6, 33, 528, 168, 60); break; diff --git a/d2bs/kolbot/libs/TorchSystem.js b/d2bs/kolbot/libs/TorchSystem.js index ccba99f83..53768cdf2 100644 --- a/d2bs/kolbot/libs/TorchSystem.js +++ b/d2bs/kolbot/libs/TorchSystem.js @@ -6,6 +6,7 @@ var TorchSystem = { LogKeys: false, + LogOrgans: true, FarmerProfiles: { // ############################ S E T U P ########################################## @@ -33,7 +34,7 @@ var TorchSystem = { // Edit here! - "Farmer 1": { // Farmer profile name + "PROFILE NAME": { // Farmer profile name // Put key finder profiles here. Example - KeyFinderProfiles: ["MF 1", "MF 2"], KeyFinderProfiles: [""], @@ -167,6 +168,10 @@ var TorchSystem = { } } + if (me.getStat(14) >= 100000) { + gold(100000); + } + delay(5000); quit(); //delay(10000); diff --git a/d2bs/kolbot/libs/bots/Andariel.js b/d2bs/kolbot/libs/bots/Andariel.js index c6977df5d..998797527 100644 --- a/d2bs/kolbot/libs/bots/Andariel.js +++ b/d2bs/kolbot/libs/bots/Andariel.js @@ -19,17 +19,9 @@ function Andariel() { } for (i = 0; i < 300; i += 1) { - if (!me.getState(121)) { - Skill.cast(Config.AttackSkill[1], ClassAttack.skillHand[1], target); - } else { - if (Config.AttackSkill[2] > -1) { - Skill.cast(Config.AttackSkill[2], ClassAttack.skillHand[2], target); - } else { - delay(300); - } - } + ClassAttack.doCast(target, Config.AttackSkill[1], Config.AttackSkill[2]); - if (target.mode === 0 || target.mode === 12) { + if (target.dead) { return true; } @@ -38,7 +30,7 @@ function Andariel() { } } - return target.mode === 0 || target.mode === 12; + return target.dead; }; Town.doChores(); diff --git a/d2bs/kolbot/libs/bots/AutoBaal.js b/d2bs/kolbot/libs/bots/AutoBaal.js index 6548cefc5..30332e685 100644 --- a/d2bs/kolbot/libs/bots/AutoBaal.js +++ b/d2bs/kolbot/libs/bots/AutoBaal.js @@ -108,15 +108,7 @@ function AutoBaal() { if (Attack.checkResist(monster, Attack.getSkillElement(Config.AttackSkill[index]))) { if (Config.AttackSkill[index] > -1) { - if (!me.getState(121)) { - Skill.cast(Config.AttackSkill[index], ClassAttack.skillHand[index], monster); - } else if (Config.AttackSkill[index + 1] > -1) { - Skill.cast(Config.AttackSkill[index + 1], ClassAttack.skillHand[index + 1], monster); - } else { - while (me.getState(121)) { - delay(40); - } - } + ClassAttack.doCast(monster, Config.AttackSkill[index], Config.AttackSkill[index + 1]); } } else { monList.shift(); diff --git a/d2bs/kolbot/libs/bots/Baal.js b/d2bs/kolbot/libs/bots/Baal.js index 48059c215..b901978ca 100644 --- a/d2bs/kolbot/libs/bots/Baal.js +++ b/d2bs/kolbot/libs/bots/Baal.js @@ -197,14 +197,8 @@ function Baal() { }; Town.doChores(); - - if (Config.RandomPrecast) { - Pather.useWaypoint("random"); - Precast.doPrecast(true); - } else { - Pather.useWaypoint(129); - Precast.doPrecast(true); - } + Pather.useWaypoint(Config.RandomPrecast ? "random" : 129); + Precast.doPrecast(true); if (me.area !== 129) { Pather.useWaypoint(129); diff --git a/d2bs/kolbot/libs/bots/BaalHelper.js b/d2bs/kolbot/libs/bots/BaalHelper.js index af656cd7c..c525ec9b0 100644 --- a/d2bs/kolbot/libs/bots/BaalHelper.js +++ b/d2bs/kolbot/libs/bots/BaalHelper.js @@ -150,7 +150,7 @@ function BaalHelper() { // experi-mental include("bots/Nihlathak.js"); try { - Nihlathak(); + Nihlathak.call(); } catch (e) { print(e); } @@ -161,7 +161,7 @@ function BaalHelper() { // experi-mental try { Town.goToTown(); - FastDiablo(); + FastDiablo.call(); } catch (e2) { print(e2); } @@ -171,14 +171,8 @@ function BaalHelper() { // experi-mental Town.goToTown(5); Town.doChores(); - - if (Config.RandomPrecast) { - Pather.useWaypoint("random"); - Precast.doPrecast(true); - } else { - Pather.useWaypoint(129); - Precast.doPrecast(true); - } + Pather.useWaypoint(Config.RandomPrecast ? "random" : 129); + Precast.doPrecast(true); if (Config.BaalHelper.SkipTP) { if (me.area !== 129) { @@ -195,7 +189,7 @@ WSKLoop: if (party) { do { - if (party.area === 131) { + if ((!Config.Leader || party.name === Config.Leader) && party.area === 131) { break WSKLoop; } } while (party.getNext()); @@ -205,7 +199,7 @@ WSKLoop: } if (i === Config.BaalHelper.Wait) { - throw new Error("No players in Throne."); + throw new Error("Player wait timed out (" + (Config.Leader ? "Leader not" : "No players") + " found in Throne)"); } for (i = 0; i < 3; i += 1) { @@ -226,15 +220,19 @@ WSKLoop: throw new Error("Failed to move to WSK3."); } - if (!Pather.moveToExit(131, true) || !Pather.moveTo(15113, 5040)) { + if (!Pather.moveToExit(131, true)) { throw new Error("Failed to move to Throne of Destruction."); } + + if (!Pather.moveTo(15113, 5040)) { + D2Bot.printToConsole("path fail"); + } } else { Pather.useWaypoint(109); Town.move("portalspot"); for (i = 0; i < Config.BaalHelper.Wait; i += 1) { - if (Pather.usePortal(131, Config.Leader || null)) { + if (Pather.getPortal(131, Config.Leader || null) && Pather.usePortal(131, Config.Leader || null)) { break; } @@ -242,7 +240,7 @@ WSKLoop: } if (i === Config.BaalHelper.Wait) { - throw new Error("No portals to Throne."); + throw new Error("Player wait timed out (" + (Config.Leader ? "No leader" : "No player") + " portals found)"); } } diff --git a/d2bs/kolbot/libs/bots/Cows.js b/d2bs/kolbot/libs/bots/Cows.js index bcba61a5b..4866fdcc9 100644 --- a/d2bs/kolbot/libs/bots/Cows.js +++ b/d2bs/kolbot/libs/bots/Cows.js @@ -219,6 +219,7 @@ function Cows() { break; } + Town.goToTown(1); Town.doChores(); leg = this.getLeg(); diff --git a/d2bs/kolbot/libs/bots/Crafting.js b/d2bs/kolbot/libs/bots/Crafting.js new file mode 100644 index 000000000..df997b37b --- /dev/null +++ b/d2bs/kolbot/libs/bots/Crafting.js @@ -0,0 +1,550 @@ +/** +* @filename Crafting.js +* @author kolton +* @desc Part of CraftingSystem +*/ + +var info, + gameRequest = false; + +function Crafting() { + var i, npcName, num; + + info = CraftingSystem.getInfo(); + + if (!info || !info.worker) { + throw new Error("Bad Crafting System config."); + } + + me.maxgametime = 0; + Town.goToTown(1); + Town.doChores(); + Town.move("stash"); + updateInfo(); + pickItems(); + + addEventListener('copydata', + function (mode, msg) { + var i, obj, rval; + + if (mode === 0) { + try { + obj = JSON.parse(msg); + } catch (e) { + return false; + } + + if (obj) { + switch (obj.name) { + case "GetGame": + if (info.Collectors.indexOf(obj.profile) > -1) { + print("GetGame: " + obj.profile); + sendCopyData(null, obj.profile, 4, me.gamename + "/" + me.gamepassword); + + gameRequest = true; + } + + break; + case "GetSetInfo": + if (info.Collectors.indexOf(obj.profile) > -1) { + print("GetSetInfo: " + obj.profile); + + rval = []; + + for (i = 0; i < info.Sets.length; i += 1) { + rval.push(info.Sets[i].Enabled ? 1 : 0); + } + + print(rval); + + sendCopyData(null, obj.profile, 4, JSON.stringify({name: "SetInfo", value: rval})); + } + + break; + } + } + } + + return true; + }); + + for (i = 0; i < Cubing.recipes.length; i += 1) { + Cubing.recipes[i].Level = 0; + } + + while (true) { + for (i = 0; i < info.Sets.length; i += 1) { + switch (info.Sets[i].Type) { + case "crafting": + num = 0; + npcName = getNPCName(info.Sets[i].BaseItems); + + if (npcName) { + num = countItems(info.Sets[i].BaseItems, 4); + + if (num < info.Sets[i].SetAmount) { + shopStuff(npcName, info.Sets[i].BaseItems, info.Sets[i].SetAmount); + } + } + + break; + case "cubing": // Nothing to do currently + break; + case "runewords": // Nothing to do currently + break; + } + } + + if (me.act !== 1) { + Town.goToTown(1); + Town.move("stash"); + } + + if (gameRequest) { + for (i = 0; i < 10; i += 1) { + if (othersInGame()) { + while (othersInGame()) { + delay(200); + } + + break; + } else { + break; + } + + delay(1000); + } + + gameRequest = false; + } + + pickItems(); + Cubing.update(); + Runewords.buildLists(); + Cubing.doCubing(); + Runewords.makeRunewords(); + delay(2000); + } +} + +function getNPCName(idList) { + var i; + + for (i = 0; i < idList.length; i += 1) { + switch (idList[i]) { + case 345: // Light Belt + case 391: // Sharkskin Belt + return "elzix"; + case 346: // Belt + case 392: // Mesh Belt + case 342: // Light Plated Boots + case 388: // Battle Boots + return "fara"; + } + } + + return false; +} + +function othersInGame() { + var p = getParty(); + + if (p) { + do { + if (p.name !== me.name) { + return true; + } + } while (p.getNext()); + } + + return false; +} + +function countItems(idList, quality) { + var item, + count = 0; + + item = me.getItem(-1, 0); + + if (item) { + do { + if (idList.indexOf(item.classid) > -1 && item.quality === quality) { + count += 1; + } + } while (item.getNext()); + } + + return count; +} + +function updateInfo() { + var i, j, items; + + if (info) { + items = me.findItems(-1, 0); + + for (i = 0; i < info.Sets.length; i += 1) { +MainSwitch: + switch (info.Sets[i].Type) { + // Always enable crafting because the base can be shopped + // Recipes with bases that can't be shopped don't need to be used with CraftingSystem + case "crafting": + info.Sets[i].Enabled = true; + + break; + // Enable only if we have a viable item to cube + // Currently the base needs to be added manually to the crafter + case "cubing": + if (!items) { + items = []; + } + + // Enable the recipe if we have an item that matches both bases list and Cubing list + // This is not a perfect check, it might not handle every case + for (j = 0; j < items.length; j += 1) { + if (info.Sets[i].BaseItems.indexOf(items[j].classid) > -1 && // Item is on the bases list + AutoMule.cubingIngredient(items[j])) { // Item is a valid Cubing ingredient + print("Base found: " + items[j].classid); + + info.Sets[i].Enabled = true; + + break MainSwitch; + } + } + + info.Sets[i].Enabled = false; + + break; + // Enable only if we have a viable runeword base + // Currently the base needs to be added manually to the crafter + case "runewords": + if (!items) { + items = []; + } + + // Enable the recipe if we have an item that matches both bases list and Cubing list + // This is not a perfect check, it might not handle every case + for (j = 0; j < items.length; j += 1) { + if (info.Sets[i].BaseItems.indexOf(items[j].classid) > -1 && // Item is on the bases list + runewordIngredient(items[j])) { // Item is a valid Runeword ingredient + print("Base found: " + items[j].classid); + + info.Sets[i].Enabled = true; + + break MainSwitch; + } + } + + info.Sets[i].Enabled = false; + + break; + } + } + + return true; + } + + return false; +} + +function runewordIngredient(item) { + if (Runewords.validGids.indexOf(item.gid) > -1) { + return true; + } + + var i, base, baseGids; + + baseGids = []; + + for (i = 0; i < Config.Runewords.length; i += 1) { + base = Runewords.getBase(Config.Runewords[i][0], Config.Runewords[i][1]) || Runewords.getBase(Config.Runewords[i][0], Config.Runewords[i][1], true); + + if (base) { + baseGids.push(base.gid); + } + } + + if (baseGids.indexOf(item.gid) > -1) { + return true; + } + + return false; +} + +function pickItems() { + var items = [], + item = getUnit(4, -1, 3); + + if (item) { + updateInfo(); + + do { + if (checkItem(item) || item.classid === 523 || Pickit.checkItem(item).result > 0) { + items.push(copyUnit(item)); + } + } while (item.getNext()); + } + + while (items.length) { + if (Pickit.canPick(items[0]) && Storage.Inventory.CanFit(items[0])) { + Pickit.pickItem(items[0]); + } + + items.shift(); + delay(1); + } + + Town.stash(); +} + +function checkItem(item) { + var i; + + for (i = 0; i < info.Sets.length; i += 1) { + if (info.Sets[i].Enabled) { + switch (info.Sets[i].Type) { + case "crafting": + // Magic item + if (item.quality === 4 && info.Sets[i].BaseItems.indexOf(item.classid) > -1) { + return true; // Valid crafting base + } + + if (info.Sets[i].Ingredients.indexOf(item.classid) > -1) { + return true; // Valid crafting ingredient + } + + break; + case "cubing": + // There is no base check, item has to be put manually on the character + + if (info.Sets[i].Ingredients.indexOf(item.classid) > -1) { + return true; + } + + break; + case "runewords": + // There is no base check, item has to be put manually on the character + + if (info.Sets[i].Ingredients.indexOf(item.classid) > -1) { + return true; + } + + break; + } + } + } + + return false; +} + +function shopStuff(npcId, classids, amount) { + print("shopStuff: " + npcId + " " + amount); + + var wpArea, town, path, menuId, npc, tickCount, + leadTimeout = 30, + leadRetry = 3; + + this.mover = function (npc, path) { + var i, j; + + path = this.processPath(npc, path); + + for (i = 0; i < path.length; i += 2) { + Pather.moveTo(path[i] - 3, path[i + 1] - 3); + moveNPC(npc, path[i], path[i + 1]); + + for (j = 0; j < leadTimeout; j += 1) { + while (npc.mode === 2) { + delay(100); + } + + if (getDistance(npc.x, npc.y, path[i], path[i + 1]) < 4) { + break; + } + + if (j > 0 && j % leadRetry === 0) { + moveNPC(npc, path[i], path[i + 1]); + } + + delay(1000); + } + + if (j === leadTimeout) { + return false; + } + } + + delay(1000); + + return true; + }; + + this.processPath = function (npc, path) { + var i, + cutIndex = 0, + dist = 100; + + for (i = 0; i < path.length; i += 2) { + if (getDistance(npc, path[i], path[i + 1]) < dist) { + cutIndex = i; + dist = getDistance(npc, path[i], path[i + 1]); + } + } + + return path.slice(cutIndex); + }; + + this.shopItems = function (classids, amount) { + var i, items, + num = 0, + npc = getInteractedNPC(); + + if (npc) { + items = npc.getItems(); + + if (items) { + for (i = 0; i < items.length; i += 1) { + if (Storage.Inventory.CanFit(items[i]) && + Pickit.canPick(items[i]) && + me.getStat(14) + me.getStat(15) >= items[i].getItemCost(0) && + classids.indexOf(items[i].classid) > -1) { + + //print("Bought " + items[i].name); + items[i].buy(); + + num = countItems(classids, 4); + + if (num >= amount) { + return true; + } + } + } + } + } + + return gameRequest; + }; + + Town.doChores(); + + switch (npcId.toLowerCase()) { + case "fara": + wpArea = 48; + town = 40; + path = [5112, 5094, 5092, 5096, 5078, 5098, 5070, 5085]; + menuId = "Repair"; + + if (!Town.goToTown(2) || !Town.move(NPC.Fara)) { + throw new Error("Failed to get to NPC"); + } + + npc = getUnit(1, NPC.Fara); + + break; + case "elzix": + wpArea = 48; + town = 40; + path = [5038, 5099, 5059, 5102, 5068, 5090, 5067, 5086]; + menuId = "Shop"; + + Town.goToTown(2); + + if (!getUnit(1, NPC.Elzix)) { + Town.move(NPC.Elzix); + } + + npc = getUnit(1, NPC.Elzix); + + break; + case "drognan": + wpArea = 48; + town = 40; + path = [5093, 5049, 5088, 5060, 5093, 5079, 5078, 5087, 5070, 5085]; + menuId = "Shop"; + + if (!Town.goToTown(2) || !Town.move(NPC.Drognan)) { + throw new Error("Failed to get to NPC"); + } + + npc = getUnit(1, NPC.Drognan); + + break; + case "ormus": + wpArea = 101; + town = 75; + path = [5147, 5089, 5156, 5075, 5157, 5063, 5160, 5050]; + menuId = "Shop"; + + if (!Town.goToTown(3) || !Town.move(NPC.Ormus)) { + throw new Error("Failed to get to NPC"); + } + + npc = getUnit(1, NPC.Ormus); + + break; + case "anya": + wpArea = 129; + town = 109; + path = [5122, 5119, 5129, 5105, 5123, 5087, 5115, 5068]; + menuId = "Shop"; + + if (!Town.goToTown(5) || !Town.move(NPC.Anya)) { + throw new Error("Failed to get to NPC"); + } + + npc = getUnit(1, NPC.Anya); + + break; + case "malah": + wpArea = 113; + town = 109; + path = [5077, 5032, 5089, 5025, 5100, 5021, 5106, 5051, 5116, 5071]; + menuId = "Shop"; + + if (!Town.goToTown(5) || !Town.move(NPC.Malah)) { + throw new Error("Failed to get to NPC"); + } + + npc = getUnit(1, NPC.Malah); + + break; + default: + throw new Error("Invalid shopbot NPC."); + } + + if (!npc) { + throw new Error("Failed to find NPC."); + } + + if (!this.mover(npc, path)) { + throw new Error("Failed to move NPC"); + } + + Town.move("waypoint"); + + tickCount = getTickCount(); + + while (true) { + if (me.area === town) { + if (npc.startTrade(menuId)) { + if (this.shopItems(classids, amount)) { + return true; + } + } + + me.cancel(); + } + + if (me.area === town) { + Pather.useWaypoint(wpArea); + } + + if (me.area === wpArea) { + Pather.useWaypoint(town); + } + + delay(5); + } + + return true; +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/Diablo.js b/d2bs/kolbot/libs/bots/Diablo.js index dcaf1a995..6b1c312e7 100644 --- a/d2bs/kolbot/libs/bots/Diablo.js +++ b/d2bs/kolbot/libs/bots/Diablo.js @@ -7,6 +7,20 @@ function Diablo() { // Sort function this.sort = function (a, b) { + if (Config.BossPriority) { + if ((a.spectype & 0x5) && (b.spectype & 0x5)) { + return getDistance(me, a) - getDistance(me, b); + } + + if (a.spectype & 0x5) { + return -1; + } + + if (b.spectype & 0x5) { + return 1; + } + } + // Entrance to Star / De Seis if (me.y > 5325 || me.y < 5260) { if (a.y > b.y) { @@ -112,6 +126,48 @@ function Diablo() { return false; }; + this.chaosPreattack = function (name, amount) { + var i, n, target, positions; + + switch (me.classid) { + case 0: + break; + case 1: + break; + case 2: + break; + case 3: + target = getUnit(1, name); + + if (!target) { + return; + } + + positions = [[6, 11], [0, 8], [8, -1], [-9, 2], [0, -11], [8, -8]]; + + for (i = 0; i < positions.length; i += 1) { + if (Attack.validSpot(target.x + positions[i][0], target.y + positions[i][1])) { // check if we can move there + Pather.moveTo(target.x + positions[i][0], target.y + positions[i][1]); + Skill.setSkill(Config.AttackSkill[2], 0); + + for (n = 0; n < amount; n += 1) { + Skill.cast(Config.AttackSkill[1], 1); + } + + break; + } + } + + break; + case 4: + break; + case 5: + break; + case 6: + break; + } + }; + this.getBoss = function (name) { var i, boss, glow = getUnit(2, 131); @@ -120,6 +176,8 @@ function Diablo() { boss = getUnit(1, name); if (boss) { + this.chaosPreattack(name, 8); + return Attack.clear(40, 0, name, this.sort); } @@ -264,21 +322,20 @@ function Diablo() { }; this.followPath = function (path) { - var i, - cleared = []; + var i; for (i = 0; i < path.length; i += 2) { - if (cleared.length) { - this.clearStrays(cleared); + if (this.cleared.length) { + this.clearStrays(); } - Pather.moveTo(path[i], path[i + 1]); + Pather.moveTo(path[i], path[i + 1], 3, getDistance(me, path[i], path[i + 1]) > 50); Attack.clear(30, 0, false, this.sort); // Push cleared positions so they can be checked for strays - cleared.push([path[i], path[i + 1]]); + this.cleared.push([path[i], path[i + 1]]); - // After 5 nodes go back 3 nodes to check for monsters + // After 5 nodes go back 2 nodes to check for monsters if (i === 10 && path.length > 16) { path = path.slice(6); i = 0; @@ -286,29 +343,70 @@ function Diablo() { } }; - this.clearStrays = function (cleared) { + this.clearStrays = function () { + /*if (!Config.PublicMode) { + return false; + }*/ + var i, - unit = getUnit(1); + oldPos = {x: me.x, y: me.y}, + monster = getUnit(1); - if (unit) { + if (monster) { do { - if (Attack.checkMonster(unit)) { - for (i = 0; i < cleared.length; i += 1) { - if (getDistance(unit, cleared[i][0], cleared[i][1]) < 30 && Attack.validSpot(unit.x, unit.y)) { - //me.overhead("we got a stray"); - Pather.moveToUnit(unit); - Attack.clear(20, 0, false, this.sort); + if (Attack.checkMonster(monster)) { + for (i = 0; i < this.cleared.length; i += 1) { + if (getDistance(monster, this.cleared[i][0], this.cleared[i][1]) < 30 && Attack.validSpot(monster.x, monster.y)) { + me.overhead("we got a stray"); + Pather.moveToUnit(monster); + Attack.clear(15, 0, false, this.sort); break; } } } - } while (unit.getNext()); + } while (monster.getNext()); + } + + if (getDistance(me, oldPos.x, oldPos.y) > 5) { + Pather.moveTo(oldPos.x, oldPos.y); } return true; }; + this.defendPlayers = function () { + var player, + oldPos = {x: me.x, y: me.y}, + monster = getUnit(1); + + if (monster) { + do { + if (Attack.checkMonster(monster)) { + player = getUnit(0); + + if (player) { + do { + if (player.name !== me.name && getDistance(monster, player) < 30) { + me.overhead("defending players"); + Pather.moveToUnit(monster); + Attack.clear(15, 0, false, this.sort); + } + } while (player.getNext()); + } + } + } while (monster.getNext()); + } + + if (getDistance(me, oldPos.x, oldPos.y) > 5) { + Pather.moveTo(oldPos.x, oldPos.y); + } + + return true; + }; + + this.cleared = []; + // path coordinates this.entranceToStar = [7794, 5517, 7791, 5491, 7768, 5459, 7775, 5424, 7817, 5458, 7777, 5408, 7769, 5379, 7777, 5357, 7809, 5359, 7805, 5330, 7780, 5317, 7791, 5293]; this.starToVizA = [7759, 5295, 7734, 5295, 7716, 5295, 7718, 5276, 7697, 5292, 7678, 5293, 7665, 5276, 7662, 5314]; @@ -320,9 +418,13 @@ function Diablo() { // start Town.doChores(); - Pather.useWaypoint(107); + Pather.useWaypoint(Config.RandomPrecast ? "random" : 107); Precast.doPrecast(true); + if (me.area !== 107) { + Pather.useWaypoint(107); + } + if (!Pather.moveTo(7790, 5544)) { throw new Error("Failed to move to Chaos Sanctuary"); } @@ -359,7 +461,18 @@ function Diablo() { this.seisSeal(); Precast.doPrecast(true); this.infectorSeal(); - Pather.moveTo(7788, 5292); + + switch (me.classid) { + case 1: + Pather.moveTo(7792, 5294); + + break; + default: + Pather.moveTo(7788, 5292); + + break; + } + if (Config.PublicMode) { say(Config.Diablo.DiabloMsg); diff --git a/d2bs/kolbot/libs/bots/DiabloHelper.js b/d2bs/kolbot/libs/bots/DiabloHelper.js index 96eb50b91..6c88abae8 100644 --- a/d2bs/kolbot/libs/bots/DiabloHelper.js +++ b/d2bs/kolbot/libs/bots/DiabloHelper.js @@ -7,6 +7,20 @@ function DiabloHelper() { // Sort function this.sort = function (a, b) { + if (Config.BossPriority) { + if ((a.spectype & 0x5) && (b.spectype & 0x5)) { + return getDistance(me, a) - getDistance(me, b); + } + + if (a.spectype & 0x5) { + return -1; + } + + if (b.spectype & 0x5) { + return 1; + } + } + // Entrance to Star / De Seis if (me.y > 5325 || me.y < 5260) { if (a.y > b.y) { @@ -42,7 +56,7 @@ function DiabloHelper() { var sealPreset = getPresetUnit(108, 2, seal); if (!seal) { - throw new Error("Seal preset not found. Can't continue."); + throw new Error("Seal preset not found. Can't continue"); } if (sealPreset.roomy * 5 + sealPreset.y === value || sealPreset.roomx * 5 + sealPreset.x === value) { @@ -252,9 +266,11 @@ function DiabloHelper() { } else { Skill.cast(Config.AttackSkill[1], 0, coords[0], coords[1]); } + + return true; } - return true; + break; case 3: break; case 6: @@ -263,10 +279,12 @@ function DiabloHelper() { if (trapCheck) { ClassAttack.placeTraps({x: coords[0], y: coords[1]}, 5); + + return true; } } - return true; + break; } return false; @@ -276,11 +294,58 @@ function DiabloHelper() { var i; for (i = 0; i < path.length; i += 2) { - Pather.moveTo(path[i], path[i + 1]); + if (this.cleared.length) { + this.clearStrays(); + } + + Pather.moveTo(path[i], path[i + 1], 3, getDistance(me, path[i], path[i + 1]) > 50); Attack.clear(30, 0, false, this.sort); + + // Push cleared positions so they can be checked for strays + this.cleared.push([path[i], path[i + 1]]); + + // After 5 nodes go back 2 nodes to check for monsters + if (i === 10 && path.length > 16) { + path = path.slice(6); + i = 0; + } } }; + this.clearStrays = function () { + /*if (!Config.PublicMode) { + return false; + }*/ + + var i, + oldPos = {x: me.x, y: me.y}, + monster = getUnit(1); + + if (monster) { + do { + if (Attack.checkMonster(monster)) { + for (i = 0; i < this.cleared.length; i += 1) { + if (getDistance(monster, this.cleared[i][0], this.cleared[i][1]) < 30 && Attack.validSpot(monster.x, monster.y)) { + me.overhead("we got a stray"); + Pather.moveToUnit(monster); + Attack.clear(15, 0, false, this.sort); + + break; + } + } + } + } while (monster.getNext()); + } + + if (getDistance(me, oldPos.x, oldPos.y) > 5) { + Pather.moveTo(oldPos.x, oldPos.y); + } + + return true; + }; + + this.cleared = []; + // path coordinates this.entranceToStar = [7794, 5517, 7791, 5491, 7768, 5459, 7775, 5424, 7817, 5458, 7777, 5408, 7769, 5379, 7777, 5357, 7809, 5359, 7805, 5330, 7780, 5317, 7774, 5305]; this.starToVizA = [7759, 5295, 7734, 5295, 7716, 5295, 7718, 5276, 7697, 5292, 7678, 5293, 7665, 5276, 7662, 5314]; @@ -290,39 +355,94 @@ function DiabloHelper() { this.starToInfA = [7809, 5268, 7834, 5306, 7852, 5280, 7852, 5310, 7869, 5294, 7895, 5295, 7919, 5290]; this.starToInfB = [7809, 5268, 7834, 5306, 7852, 5280, 7852, 5310, 7869, 5294, 7895, 5274, 7927, 5275, 7932, 5297, 7923, 5313]; - var i, partybaal, areaCheck; + var i, party; // start Town.doChores(); - Pather.useWaypoint(107); - Precast.doPrecast(true); - Pather.useWaypoint(103); - Town.move("portalspot"); - for (i = 0; i < Config.DiabloHelper.Wait; i += 1) { - partybaal = getParty(); + if (Config.DiabloHelper.SkipIfBaal) { +AreaInfoLoop: + while (true) { + me.overhead("Getting party area info"); + + if (Misc.getPlayerCount() <= 1) { + throw new Error("Empty game"); // Alone in game + } + + party = getParty(); + + if (party) { + do { + if (party.name !== me.name && party.area) { + break AreaInfoLoop; // Can read player area + } + } while (party.getNext()); + } - if (partybaal) { + delay(1000); + } + + party = getParty(); + + if (party) { do { - if (!areaCheck && partybaal.name !== me.name && partybaal.area) { - areaCheck = true; + if (party.area === 131 || party.area === 132) { // Player is in Throne of Destruction or Worldstone Chamber + return false; // End script } + } while (party.getNext()); + } + } - if (partybaal.area === 131) { - return false; - } - } while (partybaal.getNext()); + Pather.useWaypoint(Config.RandomPrecast ? "random" : 107); + Precast.doPrecast(true); + + if (Config.DiabloHelper.SkipTP) { + if (me.area !== 107) { + Pather.useWaypoint(107); } - if (areaCheck && Pather.usePortal(108, null)) { - break; + if (!Pather.moveTo(7790, 5544)) { + throw new Error("Failed to move to Chaos Sanctuary"); } - delay(1000); - } + if (!Config.DiabloHelper.Entrance) { + Pather.moveTo(7774, 5305); + } + +CSLoop: + for (i = 0; i < Config.DiabloHelper.Wait; i += 1) { + party = getParty(); - if (i === Config.DiabloHelper.Wait) { - throw new Error("No portals to Chaos"); + if (party) { + do { + if (party.name !== me.name && party.area === 108 && (!Config.Leader || party.name === Config.Leader)) { + break CSLoop; + } + } while (party.getNext()); + } + + Attack.clear(30, 0, false, this.sort); + delay(1000); + } + + if (i === Config.DiabloHelper.Wait) { + throw new Error("Player wait timed out (" + (Config.Leader ? "Leader not" : "No players") + " found in Chaos)"); + } + } else { + Pather.useWaypoint(103); + Town.move("portalspot"); + + for (i = 0; i < Config.DiabloHelper.Wait; i += 1) { + if (Pather.getPortal(108, Config.Leader || null) && Pather.usePortal(108, Config.Leader || null)) { + break; + } + + delay(1000); + } + + if (i === Config.DiabloHelper.Wait) { + throw new Error("Player wait timed out (" + (Config.Leader ? "No leader" : "No player") + " portals found)"); + } } this.initLayout(); @@ -341,7 +461,18 @@ function DiabloHelper() { this.seisSeal(); Precast.doPrecast(true); this.infectorSeal(); - Pather.moveTo(7788, 5292); + + switch (me.classid) { + case 1: + Pather.moveTo(7793, 5291); + + break; + default: + Pather.moveTo(7788, 5292); + + break; + } + this.diabloPrep(); Attack.kill(243); // Diablo Pickit.pickItems(); diff --git a/d2bs/kolbot/libs/bots/Duriel.js b/d2bs/kolbot/libs/bots/Duriel.js index 7015ec1ae..60754510f 100644 --- a/d2bs/kolbot/libs/bots/Duriel.js +++ b/d2bs/kolbot/libs/bots/Duriel.js @@ -1 +1 @@ -/** * @filename Duriel.js * @author kolton * @desc kill Duriel */ function Duriel() { this.killDuriel = function () { var i, target; for (i = 0; i < 3; i += 1) { target = getUnit(1, 211); if (target) { break; } delay(500); } if (!target) { throw new Error("Duriel not found."); } if (Config.MFLeader) { Pather.makePortal(); say("kill " + 211); } for (i = 0; i < 300; i += 1) { if (!me.getState(121)) { Skill.cast(Config.AttackSkill[1], ClassAttack.skillHand[1], target); } else { if (Config.AttackSkill[2] > -1) { Skill.cast(Config.AttackSkill[2], ClassAttack.skillHand[2], target); } else { delay(300); } } if (target.mode === 0 || target.mode === 12) { return true; } if (getDistance(me, target) <= 10) { Pather.moveTo(22638, me.y < target.y ? 15722 : 15693); } } return target.mode === 0 || target.mode === 12; }; var i; Town.doChores(); Pather.useWaypoint(46); Precast.doPrecast(true); if (!Pather.moveToExit(getRoom().correcttomb, true) || !Pather.moveToPreset(me.area, 2, 152, -3, -3)) { throw new Error("Failed to move to Duriel"); } delay(1000); if (me.classid === 1 && me.getSkill(43, 1)) { for (i = 0; i < 3; i += 1) { if (me.area === 73) { break; } Skill.cast(43, 0, getUnit(2, 100)); } } if (me.area !== 73 && !Pather.useUnit(2, 100, 73)) { throw new Error("Failed to move to Duriel"); } if (me.classid === 1 && me.gametype === 0) { this.killDuriel(); } else { Attack.kill(211); // Duriel } Pickit.pickItems(); return true; } \ No newline at end of file +/** * @filename Duriel.js * @author kolton * @desc kill Duriel */ function Duriel() { this.killDuriel = function () { var i, target; for (i = 0; i < 3; i += 1) { target = getUnit(1, 211); if (target) { break; } delay(500); } if (!target) { throw new Error("Duriel not found."); } if (Config.MFLeader) { Pather.makePortal(); say("kill " + 211); } for (i = 0; i < 300; i += 1) { ClassAttack.doCast(target, Config.AttackSkill[1], Config.AttackSkill[2]); if (target.dead) { return true; } if (getDistance(me, target) <= 10) { Pather.moveTo(22638, me.y < target.y ? 15722 : 15693); } } return target.dead; }; var i, unit; Town.doChores(); Pather.useWaypoint(46); Precast.doPrecast(true); 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"); } for (i = 0; i < 10; i += 1) { if (getUnit(2, 100)) { break; } delay(500); } if (me.gametype === 1 && me.classid !== 1) { Attack.clear(5); } unit = getUnit(2, 100); if (unit) { for (i = 0; i < 3; i += 1) { if (me.area === unit.area) { Skill.cast(43, 0, unit); } if (me.area === 73) { break; } } } if (me.area !== 73 && !Pather.useUnit(2, 100, 73)) { Attack.clear(10); Pather.useUnit(2, 100, 73); } if (me.area !== 73) { throw new Error("Failed to move to Duriel"); } if (me.classid === 1 && me.gametype === 0) { this.killDuriel(); } else { Attack.kill(211); // Duriel } Pickit.pickItems(); return true; } \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/Enchant.js b/d2bs/kolbot/libs/bots/Enchant.js index 8f4aefbba..12df661b8 100644 --- a/d2bs/kolbot/libs/bots/Enchant.js +++ b/d2bs/kolbot/libs/bots/Enchant.js @@ -5,9 +5,9 @@ */ function Enchant() { - var command, hostile, nick, + var command, hostile, nick, spot, tick, s, m, + startTime = getTickCount(), shitList = [], - wpNicks = {}, greet = []; this.enchant = function (nick) { @@ -17,22 +17,48 @@ function Enchant() { return false; } - var unit = getUnit(0, nick); + var partyUnit, + unit = getUnit(0, nick); - if (!unit || getDistance(me, unit) > 40) { + if (getDistance(me, unit) > 35) { say("Get closer."); return false; } + if (!unit) { + partyUnit = getParty(nick); + + // wait until party area is readable? + + if ([40, 75, 103, 109].indexOf(partyUnit.area) > -1) { + say("Wait for me at waypoint."); + Town.goToTown([1, 40, 75, 103, 109].indexOf(partyUnit.area) + 1); // index+1 for town 2,3,4,5 + + unit = getUnit(0, nick); + } else { + say("You need to be in one of the towns."); + + return false; + } + } + if (unit) { do { if (!unit.dead) { // player is alive + if (getDistance(me, unit) >= 35) { + say("You went too far away."); + + return false; + } + Skill.setSkill(52, 0); sendPacket(1, 0x11, 4, unit.type, 4, unit.gid); delay(500); } } while (unit.getNext()); + } else { + say("Couldn't find you, champ."); } unit = getUnit(1); @@ -98,7 +124,7 @@ function Enchant() { do { if (leg.name.indexOf("ÿc1") > -1) { wrongLeg = true; - } else { // For idiots trying to give leg from another difficulty + } else if (getDistance(me, leg) <= 15) { gid = leg.gid; Pickit.pickItem(leg); @@ -108,7 +134,7 @@ function Enchant() { } while (leg.getNext()); } - say("Bring the leg " + (wrongLeg ? "from this difficulty" : "") + " to me."); + say("Bring the leg " + (wrongLeg ? "from this difficulty" : "") + " close to me."); return false; } @@ -130,7 +156,10 @@ function Enchant() { } if (!portal) { - throw new Error("Tristram portal not found"); + say("Failed to enter Tristram :("); + Town.goToTown(); + + return false; } Pather.moveTo(25048, 5177); @@ -154,15 +183,37 @@ function Enchant() { } Town.goToTown(); + say("Failed to get the leg :("); return false; }; this.getTome = function () { - var tome, - myTome = me.findItem("tbk", 0, 3), - akara = Town.initNPC("Shop"); + var tome, akara, myTome; + + myTome = me.findItem("tbk", 0, 3); + tome = me.getItem("tbk"); + + // In case of 2 tomes or tome stuck in cube + if (tome) { + do { + if (!myTome || tome.gid !== myTome.gid) { + return copyUnit(tome); + } + } while (tome.getNext()); + } + + Town.move("akara"); + + akara = getUnit(1, NPC.Akara); + + if (!akara || akara.area !== me.area || getDistance(me, akara) > 20) { + say("Akara not found."); + return false; + } + + myTome = me.findItem("tbk", 0, 3); tome = me.getItem("tbk"); if (tome) { @@ -173,8 +224,12 @@ function Enchant() { } while (tome.getNext()); } + akara = Town.initNPC("Shop"); + if (!akara) { - throw new Error("Failed to buy tome"); + say("Failed to buy tome :("); + + return false; } tome = akara.getItem("tbk"); @@ -273,12 +328,16 @@ function Enchant() { }; this.getWpNick = function (nick) { - if (wpNicks.hasOwnProperty(nick)) { - if (wpNicks[nick].requests > 4) { + if (!this.wpNicks) { + this.wpNicks = {}; + } + + if (this.wpNicks.hasOwnProperty(nick)) { + if (this.wpNicks[nick].requests > 4) { return "maxrequests"; } - if (getTickCount() - wpNicks[nick].timer < 60000) { + if (getTickCount() - this.wpNicks[nick].timer < 60000) { return "mintime"; } @@ -289,7 +348,7 @@ function Enchant() { }; this.addWpNick = function (nick) { - wpNicks[nick] = {timer: getTickCount(), requests: 0}; + this.wpNicks[nick] = {timer: getTickCount(), requests: 0}; }; this.giveWps = function (nick) { @@ -372,12 +431,12 @@ MainLoop: } } - Town.goToTown(1); Town.doChores(); + Town.goToTown(1); Town.move("portalspot"); - wpNicks[nick].requests += 1; - wpNicks[nick].timer = getTickCount(); + this.wpNicks[nick].requests += 1; + this.wpNicks[nick].timer = getTickCount(); return true; }; @@ -431,6 +490,56 @@ MainLoop: return rval; }; + this.floodCheck = function (command) { + var cmd = command[0], + nick = command[1]; + + if ([ "help", "timeleft", + Config.Enchant.Triggers[0].toLowerCase(), + Config.Enchant.Triggers[1].toLowerCase(), + Config.Enchant.Triggers[2].toLowerCase() + ].indexOf(cmd.toLowerCase()) === -1) { + return false; + } + + if (!this.cmdNicks) { + this.cmdNicks = {}; + } + + if (!this.cmdNicks.hasOwnProperty(nick)) { + this.cmdNicks[nick] = { + firstCmd: getTickCount(), + commands: 0, + ignored: false + }; + } + + if (this.cmdNicks[nick].ignored) { + if (getTickCount() - this.cmdNicks[nick].ignored < 60000) { + return true; // ignore flooder + } + + // unignore flooder + this.cmdNicks[nick].ignored = false; + this.cmdNicks[nick].commands = 0; + } + + this.cmdNicks[nick].commands += 1; + + if (getTickCount() - this.cmdNicks[nick].firstCmd < 10000) { + if (this.cmdNicks[nick].commands > 5) { + this.cmdNicks[nick].ignored = getTickCount(); + + say(nick + ", you are being ignored for 60 seconds because of flooding."); + } + } else { + this.cmdNicks[nick].firstCmd = getTickCount(); + this.cmdNicks[nick].commands = 0; + } + + return false; + }; + function ChatEvent(nick, msg) { command = [msg, nick]; } @@ -446,16 +555,22 @@ MainLoop: } } + // START if (Config.ShitList) { shitList = ShitList.read(); } addEventListener("chatmsg", ChatEvent); addEventListener("gameevent", GreetEvent); - Town.goToTown(1); Town.doChores(); + Town.goToTown(1); Town.move("portalspot"); + spot = { + x: me.x, + y: me.y + }; + while (true) { while (greet.length > 0) { nick = greet.shift(); @@ -465,7 +580,11 @@ MainLoop: } } - if (command) { + if (spot && getDistance(me, spot) > 10) { + Pather.moveTo(spot.x, spot.y); + } + + if (command && !this.floodCheck(command)) { switch (command[0].toLowerCase()) { case "help": this.checkHostiles(); @@ -477,14 +596,23 @@ MainLoop: } say("Commands:"); - say((Config.Enchant.Triggers[0] ? "Enhant: " + Config.Enchant.Triggers[0] : "") + + say("Remaining time: timeleft" + + (Config.Enchant.Triggers[0] ? " | Enhant: " + Config.Enchant.Triggers[0] : "") + (Config.Enchant.Triggers[1] ? " | Open cow level: " + Config.Enchant.Triggers[1] : "") + - (Config.Enchant.Triggers[2] ? " | Give waypoints: " + Config.Enchant.Triggers[2] : "")); + (Config.Enchant.Triggers[2] ? " | Give waypoints: " + Config.Enchant.Triggers[2] : "")); if (Config.Enchant.AutoChant) { say("Auto enchant is ON"); } + break; + case "timeleft": + tick = Config.Enchant.GameLength * 6e4 - getTickCount() + startTime; + m = Math.floor(tick / 60000); + s = Math.floor((tick / 1000) % 60); + + say("Time left: " + (m ? m + " minute" + (m > 1 ? "s" : "") + ", " : "") + s + " second" + (s > 1 ? "s." : ".")); + break; case Config.Enchant.Triggers[0].toLowerCase(): // chant this.checkHostiles(); @@ -534,11 +662,15 @@ MainLoop: command = ""; + if (me.act > 1) { + Town.goToTown(1); + } + if (Config.Enchant.AutoChant) { this.autoChant(); } - if (getTickCount() - me.gamestarttime >= Config.Enchant.GameLength * 6e4) { + if (getTickCount() - startTime >= Config.Enchant.GameLength * 6e4) { say("Use kolbot or die!"); delay(1000); diff --git a/d2bs/kolbot/libs/bots/FastDiablo.js b/d2bs/kolbot/libs/bots/FastDiablo.js index 5a7e340c4..a6d4e4d30 100644 --- a/d2bs/kolbot/libs/bots/FastDiablo.js +++ b/d2bs/kolbot/libs/bots/FastDiablo.js @@ -5,8 +5,6 @@ */ function FastDiablo() { - var i, tick, seal; - this.getLayout = function (seal, value) { var sealPreset = getPresetUnit(108, 2, seal); @@ -161,48 +159,59 @@ function FastDiablo() { throw new Error("Diablo not found"); }; + this.openSeal = function (classid) { + var i, j, seal; + + for (i = 0; i < 5; i += 1) { + Pather.moveToPreset(108, 2, classid, classid === 394 ? 5 : 2, classid === 394 ? 5 : 0); - this.openSeal = function (id) { - Pather.moveToPreset(108, 2, id, 4); + if (i > 1) { + Attack.clear(10); + } - seal = getUnit(2, id); + for (j = 0; j < 3; j += 1) { + seal = getUnit(2, classid); - if (seal) { - for (i = 0; i < 5; i += 1) { - if (getDistance(me, seal) > 5) { - Pather.moveToUnit(seal, 4, 0); + if (seal) { + break; } - //seal.interact(); - sendPacket(1, 0x13, 4, 0x2, 4, seal.gid); + delay(100); + } - tick = getTickCount(); + if (!seal) { + throw new Error("Seal not found (id " + classid + ")"); + } - while (getTickCount() - tick < 500) { - if (seal.mode) { - return true; - } + if (seal.mode) { + return true; + } - delay(10); - } + sendPacket(1, 0x13, 4, 0x2, 4, seal.gid); + delay(classid === 394 ? 1000 : 500); - if (i > 2) { - Attack.clear(5); + if (!seal.mode) { + if (classid === 394 && Attack.validSpot(seal.x + 15, seal.y)) { // de seis optimization + Pather.moveTo(seal.x + 15, seal.y); + } else { + Pather.moveTo(seal.x - 5, seal.y - 5); } + + delay(500); + } else { + return true; } } - return false; + throw new Error("Failed to open seal (id " + classid + ")"); }; Town.doChores(); Pather.useWaypoint(107); Precast.doPrecast(true); this.initLayout(); - - if (!this.openSeal(395) || !this.openSeal(396)) { - throw new Error("Failed to open seals"); - } + this.openSeal(395); + this.openSeal(396); if (this.vizLayout === 1) { Pather.moveTo(7691, 5292); @@ -214,9 +223,7 @@ function FastDiablo() { throw new Error("Failed to kill Vizier"); } - if (!this.openSeal(394)) { - throw new Error("Failed to open seals"); - } + this.openSeal(394); if (this.seisLayout === 1) { Pather.moveTo(7771, 5196); @@ -228,9 +235,8 @@ function FastDiablo() { throw new Error("Failed to kill de Seis"); } - if (!this.openSeal(392) || !this.openSeal(393)) { - throw new Error("Failed to open seals"); - } + this.openSeal(392); + this.openSeal(393); if (this.infLayout === 1) { delay(1); diff --git a/d2bs/kolbot/libs/bots/Follower.js b/d2bs/kolbot/libs/bots/Follower.js index 6318aa00c..dc827eb3d 100644 --- a/d2bs/kolbot/libs/bots/Follower.js +++ b/d2bs/kolbot/libs/bots/Follower.js @@ -541,7 +541,7 @@ function Follower() { Config.AttackSkill[4] = skill; Skill.setSkill(skill, 0); - Attack.init(); + //Attack.init(); } else { say("I don't have that aura."); } @@ -562,7 +562,7 @@ function Follower() { Config.AttackSkill[1] = skill; Config.AttackSkill[3] = skill; - Attack.init(); + //Attack.init(); } else { say("I don't have that skill."); } diff --git a/d2bs/kolbot/libs/bots/Gamble.js b/d2bs/kolbot/libs/bots/Gamble.js index 695b375e4..36c549da5 100644 --- a/d2bs/kolbot/libs/bots/Gamble.js +++ b/d2bs/kolbot/libs/bots/Gamble.js @@ -35,6 +35,12 @@ function Gamble() { while (needGold) { while (true) { + if (Town.needGamble()) { + needGold = false; + } + + Town.stash(); + gold = getUnit(4, 523, 3); if (!gold || !Pickit.canPick(gold)) { @@ -42,12 +48,7 @@ function Gamble() { } Pickit.pickItem(gold); - Town.stash(); delay(500); - - if (Town.needGamble()) { - needGold = false; - } } delay(500); diff --git a/d2bs/kolbot/libs/bots/KillDclone.js b/d2bs/kolbot/libs/bots/KillDclone.js index 9c41548e8..ca7f11627 100644 --- a/d2bs/kolbot/libs/bots/KillDclone.js +++ b/d2bs/kolbot/libs/bots/KillDclone.js @@ -16,8 +16,8 @@ function KillDclone() { Attack.kill(333); Pickit.pickItems(); - if (!!AutoMule.getMule(1)) { - scriptBroadcast("muleTorch"); + if (AutoMule.getInfo() && AutoMule.getInfo().hasOwnProperty("torchMuleInfo")) { + scriptBroadcast("muleAnni"); } return true; diff --git a/d2bs/kolbot/libs/bots/MFHelper.js b/d2bs/kolbot/libs/bots/MFHelper.js index 386e11f2f..3039e1105 100644 --- a/d2bs/kolbot/libs/bots/MFHelper.js +++ b/d2bs/kolbot/libs/bots/MFHelper.js @@ -5,7 +5,7 @@ */ function MFHelper() { - var i, player, playerAct, split, + var i, player, playerAct, split, area, oldCommand = "", command = ""; @@ -156,6 +156,7 @@ function MFHelper() { player = this.findPlayer(Config.Leader); } + // START MainLoop: while (true) { if (player) { @@ -182,16 +183,17 @@ MainLoop: print("ÿc4MFHelperÿc0: Kill"); split = command.split("kill ")[1]; + area = player.area; for (i = 0; i < 5; i += 1) { - if (Pather.getPortal(player.area, player.name)) { + if (Pather.usePortal(player.area, player.name)) { break; } delay(1000); } - if (Pather.usePortal(player.area, player.name)) { + if (me.area === area) { Precast.doPrecast(false); try { @@ -216,15 +218,17 @@ MainLoop: } else if (command.indexOf("clearlevel") > -1) { print("ÿc4MFHelperÿc0: Clear Level"); + area = player.area; + for (i = 0; i < 5; i += 1) { - if (Pather.getPortal(player.area, player.name)) { + if (Pather.usePortal(player.area, player.name)) { break; } delay(1000); } - if (Pather.usePortal(player.area, player.name)) { + if (me.area === area) { Precast.doPrecast(false); Attack.clearLevel(Config.ClearType); Precast.doPrecast(true); @@ -239,8 +243,17 @@ MainLoop: print("ÿc4MFHelperÿc0: Clear"); split = command.split("clear ")[1]; + area = player.area; + + for (i = 0; i < 5; i += 1) { + if (Pather.usePortal(player.area, player.name)) { + break; + } - if (Pather.usePortal(player.area, player.name)) { + delay(1000); + } + + if (me.area === area) { Precast.doPrecast(false); try { @@ -267,14 +280,14 @@ MainLoop: print("ÿc4MFHelperÿc0: Clear Cows"); for (i = 0; i < 5; i += 1) { - if (Town.goToTown(1) && Pather.getPortal(39)) { + if (Town.goToTown(1) && Pather.usePortal(39)) { break; } delay(1000); } - if (Pather.usePortal(39)) { + if (me.area === 39) { Precast.doPrecast(false); this.clearCowLevel(); delay(1000); @@ -288,15 +301,17 @@ MainLoop: } else if (command.indexOf("council") > -1) { print("ÿc4MFHelperÿc0: Kill Council"); + area = player.area; + for (i = 0; i < 5; i += 1) { - if (Pather.getPortal(player.area, player.name)) { + if (Pather.usePortal(player.area, player.name)) { break; } delay(1000); } - if (Pather.usePortal(player.area, player.name)) { + if (me.area === area) { Precast.doPrecast(false); Attack.clearList(Attack.getMob([345, 346, 347], 0, 40)); diff --git a/d2bs/kolbot/libs/bots/Mephisto.js b/d2bs/kolbot/libs/bots/Mephisto.js index 865f25c27..edac083c7 100644 --- a/d2bs/kolbot/libs/bots/Mephisto.js +++ b/d2bs/kolbot/libs/bots/Mephisto.js @@ -147,7 +147,12 @@ function Mephisto() { if (me.classid === 1) { if (Config.Mephisto.MoatTrick) { this.moat(); + + Skill.usePvpRange = true; + Attack.kill(242); // Mephisto + + Skill.usePvpRange = false; } else { //this.killMephisto(); Attack.kill(242); // Mephisto diff --git a/d2bs/kolbot/libs/bots/OrgTorch.js b/d2bs/kolbot/libs/bots/OrgTorch.js index b936c21bc..10ad6f900 100644 --- a/d2bs/kolbot/libs/bots/OrgTorch.js +++ b/d2bs/kolbot/libs/bots/OrgTorch.js @@ -28,7 +28,8 @@ function OrgTorch() { if (item.quality === 7 && Pickit.checkItem(item).result === 1) { if (AutoMule.getInfo() && AutoMule.getInfo().hasOwnProperty("torchMuleInfo")) { scriptBroadcast("muleTorch"); - quit(); + //quit(); + scriptBroadcast("quit"); //delay(10000); } @@ -410,6 +411,7 @@ function OrgTorch() { if (tkeys >= 3 && hkeys >= 3 && dkeys >= 3) { this.getFade(); print("Making organs."); + D2Bot.printToConsole("OrgTorch: Making organs.", 7); for (i = 0; i < 3; i += 1) { // Abort if we have a complete set of organs @@ -442,6 +444,7 @@ function OrgTorch() { if (brains && eyes && horns) { this.getFade(); print("Making torch"); + D2Bot.printToConsole("OrgTorch: Making torch.", 7); portal = this.openPortal(1); @@ -453,4 +456,4 @@ function OrgTorch() { } return true; -} +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/Pindleskin.js b/d2bs/kolbot/libs/bots/Pindleskin.js index 5fe23e302..05bb57302 100644 --- a/d2bs/kolbot/libs/bots/Pindleskin.js +++ b/d2bs/kolbot/libs/bots/Pindleskin.js @@ -49,16 +49,20 @@ function Pindleskin() { throw new Error("Failed to move to Halls of Vaught"); } - Pather.moveToPreset(me.area, 2, 462, 0, 0, false, true); + Pather.moveToPreset(me.area, 2, 462, 10, 10); if (Config.Pindleskin.ViperQuit && getUnit(1, 597)) { print("Tomb Vipers found."); return true; } + + if (Config.Pindleskin.ClearVipers) { + Attack.clearList(Attack.getMob(597, 0, 20)); + } Attack.kill(526); // Nihlathak - //Attack.clear(20); + //Attack.clear(15, 0, 526); Pickit.pickItems(); } diff --git a/d2bs/kolbot/libs/bots/Questing.js b/d2bs/kolbot/libs/bots/Questing.js index fa6df7534..ab97dc273 100644 --- a/d2bs/kolbot/libs/bots/Questing.js +++ b/d2bs/kolbot/libs/bots/Questing.js @@ -1 +1 @@ -/** * @filename Questing.js * @author kolton * @desc Do quests, only most popular ones for now */ function Questing() { var i, quests = [ [1, "clearDen"], [9, "killRadament"], [17, "lamEssen"], [25, "killIzual"], [35, "killShenk"], [37, "freeAnya"] ]; this.clearDen = function () { print("starting den"); var akara; if (!Town.goToTown(1) || !Pather.moveToExit([2, 8], true)) { throw new Error(); } Precast.doPrecast(true); Attack.clearLevel(); Town.goToTown(); Town.move("akara"); akara = getUnit(1, "akara"); akara.openMenu(); me.cancel(); return true; }; this.killRadament = function () { if (!Pather.accessToAct(2)) { return false; } print("starting radament"); var book, atma; if (!Town.goToTown() || !Pather.useWaypoint(48, true)) { throw new Error(); } Precast.doPrecast(true); if (!Pather.moveToExit(49, true) || !Pather.moveToPreset(me.area, 2, 355)) { throw new Error(); } Attack.kill(229); // Radament book = getUnit(4, 552); if (book) { Pickit.pickItem(book); delay(300); clickItem(1, book); } Town.goToTown(); Town.move("atma"); atma = getUnit(1, "atma"); atma.openMenu(); me.cancel(); return true; }; this.killIzual = function () { if (!Pather.accessToAct(4)) { return false; } print("starting izual"); var tyrael; if (!Town.goToTown() || !Pather.useWaypoint(106, true)) { throw new Error(); } Precast.doPrecast(true); if (!Pather.moveToPreset(105, 1, 256)) { return false; } Attack.kill(256); // Izual Town.goToTown(); Town.move("tyrael"); tyrael = getUnit(1, "tyrael"); tyrael.openMenu(); me.cancel(); if (getUnit(2, 566)) { Pather.useUnit(2, 566, 109); } return true; }; this.lamEssen = function () { if (!Pather.accessToAct(3)) { return false; } print("starting lam essen"); var stand, book, alkor; if (!Town.goToTown() || !Pather.useWaypoint(80, true)) { throw new Error(); } Precast.doPrecast(true); if (!Pather.moveToExit(94, true) || !Pather.moveToPreset(me.area, 2, 193)) { throw new Error(); } stand = getUnit(2, 193); Misc.openChest(stand); delay(300); book = getUnit(4, 548); Pickit.pickItem(book); Town.goToTown(); Town.move("alkor"); alkor = getUnit(1, "alkor"); alkor.openMenu(); me.cancel(); return true; }; this.killShenk = function () { if (!Pather.accessToAct(5)) { return false; } if (me.getQuest(35, 1)) { return true; } print("starting shenk"); if (!Town.goToTown() || !Pather.useWaypoint(111, true)) { throw new Error(); } Precast.doPrecast(true); Pather.moveTo(3883, 5113); Attack.kill(getLocaleString(22435)); // Shenk the Overseer Town.goToTown(); return true; }; this.freeAnya = function () { if (!Pather.accessToAct(5)) { return false; } if (me.getQuest(37, 1)) { return true; } print("starting anya"); var anya, malah, scroll; if (!Town.goToTown() || !Pather.useWaypoint(113, true)) { throw new Error(); } Precast.doPrecast(true); if (!Pather.moveToExit(114, true) || !Pather.moveToPreset(me.area, 2, 460)) { throw new Error(); } delay(1000); anya = getUnit(2, 558); Pather.moveToUnit(anya); anya.interact(); delay(300); me.cancel(); Town.goToTown(); Town.move("malah"); malah = getUnit(1, "malah"); malah.openMenu(); me.cancel(); Town.move("portalspot"); Pather.usePortal(114, me.name); anya.interact(); delay(300); me.cancel(); Town.goToTown(); Town.move("malah"); malah.openMenu(); me.cancel(); delay(500); scroll = me.getItem(646); if (scroll) { clickItem(1, scroll); } return true; }; for (i = 0; i < quests.length; i += 1) { if (me.inTown) { Town.doChores(); } if (!me.getQuest(quests[i][0], 0)) { try { this[quests[i][1]](); } catch (e) { print(e); print("Quest failed, moving to next one"); continue; } } } D2Bot.stop(); return true; } \ No newline at end of file +/** * @filename Questing.js * @author kolton * @desc Do quests, only most popular ones for now */ function Questing() { var i, j, quests = [ [1, "clearDen"], [9, "killRadament"], [17, "lamEssen"], [25, "killIzual"], [35, "killShenk"], [37, "freeAnya"] ]; this.checkQuest = function (id, state) { sendPacket(1, 0x40); delay(500); return me.getQuest(id, state); }; this.clearDen = function () { print("starting den"); var akara; if (!Town.goToTown(1) || !Pather.moveToExit([2, 8], true)) { throw new Error(); } Precast.doPrecast(true); Attack.clearLevel(); Town.goToTown(); Town.move("akara"); akara = getUnit(1, "akara"); akara.openMenu(); me.cancel(); return true; }; this.killRadament = function () { if (!Pather.accessToAct(2)) { return false; } print("starting radament"); var book, atma; if (!Town.goToTown() || !Pather.useWaypoint(48, true)) { throw new Error(); } Precast.doPrecast(true); if (!Pather.moveToExit(49, true) || !Pather.moveToPreset(me.area, 2, 355)) { throw new Error(); } Attack.kill(229); // Radament book = getUnit(4, 552); if (book) { Pickit.pickItem(book); delay(300); clickItem(1, book); } Town.goToTown(); Town.move("atma"); atma = getUnit(1, "atma"); atma.openMenu(); me.cancel(); return true; }; this.killIzual = function () { if (!Pather.accessToAct(4)) { return false; } print("starting izual"); var tyrael; if (!Town.goToTown() || !Pather.useWaypoint(106, true)) { throw new Error(); } Precast.doPrecast(true); if (!Pather.moveToPreset(105, 1, 256)) { return false; } Attack.kill(256); // Izual Town.goToTown(); Town.move("tyrael"); tyrael = getUnit(1, "tyrael"); tyrael.openMenu(); me.cancel(); if (getUnit(2, 566)) { Pather.useUnit(2, 566, 109); } return true; }; this.lamEssen = function () { if (!Pather.accessToAct(3)) { return false; } print("starting lam essen"); var stand, book, alkor; if (!Town.goToTown() || !Pather.useWaypoint(80, true)) { throw new Error(); } Precast.doPrecast(true); if (!Pather.moveToExit(94, true) || !Pather.moveToPreset(me.area, 2, 193)) { throw new Error(); } stand = getUnit(2, 193); Misc.openChest(stand); delay(300); book = getUnit(4, 548); Pickit.pickItem(book); Town.goToTown(); Town.move("alkor"); alkor = getUnit(1, "alkor"); alkor.openMenu(); me.cancel(); return true; }; this.killShenk = function () { if (!Pather.accessToAct(5)) { return false; } if (this.checkQuest(35, 1)) { return true; } print("starting shenk"); if (!Town.goToTown() || !Pather.useWaypoint(111, true)) { throw new Error(); } Precast.doPrecast(true); Pather.moveTo(3883, 5113); Attack.kill(getLocaleString(22435)); // Shenk the Overseer Town.goToTown(); return true; }; this.freeAnya = function () { if (!Pather.accessToAct(5)) { return false; } if (this.checkQuest(37, 1)) { return true; } print("starting anya"); var anya, malah, scroll; if (!Town.goToTown() || !Pather.useWaypoint(113, true)) { throw new Error(); } Precast.doPrecast(true); if (!Pather.moveToExit(114, true) || !Pather.moveToPreset(me.area, 2, 460)) { throw new Error(); } delay(1000); anya = getUnit(2, 558); Pather.moveToUnit(anya); //anya.interact(); sendPacket(1, 0x13, 4, 0x2, 4, anya.gid); delay(300); me.cancel(); Town.goToTown(); Town.move("malah"); malah = getUnit(1, "malah"); malah.openMenu(); me.cancel(); Town.move("portalspot"); Pather.usePortal(114, me.name); anya.interact(); delay(300); me.cancel(); Town.goToTown(); Town.move("malah"); malah.openMenu(); me.cancel(); delay(500); scroll = me.getItem(646); if (scroll) { clickItem(1, scroll); } return true; }; for (i = 0; i < quests.length; i += 1) { if (me.inTown) { Town.doChores(); } for (j = 0; j < 3; j += 1) { if (!this.checkQuest(quests[i][0], 0)) { try { if (this[quests[i][1]]()) { break; } } catch (e) { } } else { break; } } if (j === 3) { D2Bot.printToConsole("Quest " + quests[i][1] + " failed."); } } D2Bot.printToConsole("All quests done. Stopping profile."); D2Bot.stop(); return true; } \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/Rakanishu.js b/d2bs/kolbot/libs/bots/Rakanishu.js index e6bbe4213..2e74e4a7f 100644 --- a/d2bs/kolbot/libs/bots/Rakanishu.js +++ b/d2bs/kolbot/libs/bots/Rakanishu.js @@ -15,7 +15,7 @@ function Rakanishu() { Attack.clear(15, 0, getLocaleString(2872)); // Rakanishu - if (Config.Rakanishu.KillGriswold && me.getQuest(4, 3)) { + if (Config.Rakanishu.KillGriswold && me.getQuest(4, 4)) { if (!Pather.usePortal(38)) { throw new Error("Failed to move to Tristram"); } diff --git a/d2bs/kolbot/libs/bots/Rushee.js b/d2bs/kolbot/libs/bots/Rushee.js index 4d84e09c6..53955b8ff 100644 --- a/d2bs/kolbot/libs/bots/Rushee.js +++ b/d2bs/kolbot/libs/bots/Rushee.js @@ -39,6 +39,20 @@ function Rushee() { return 5; }; + this.revive = function () { + while (me.mode === 0) { + delay(40); + } + + if (me.mode === 17) { + me.revive(); + + while (!me.inTown) { + delay(40); + } + } + }; + this.checkQuest = function (id, state) { sendPacket(1, 0x40); delay(500); @@ -83,7 +97,7 @@ function Rushee() { var monster = getUnit(1, classid); if (monster) { - while (monster.mode !== 12) { + while (monster.mode !== 12 && monster.mode !== 0) { delay(500); } @@ -131,6 +145,7 @@ function Rushee() { Storage.Cube.MoveTo(amulet); Storage.Cube.MoveTo(staff); Cubing.openCube(); + print("making staff"); transmute(); delay(750 + me.ping); Cubing.emptyCube(); @@ -140,7 +155,7 @@ function Rushee() { }; this.placeStaff = function () { - var staff, + var staff, item, tick = getTickCount(), orifice = getUnit(2, 152); @@ -164,6 +179,13 @@ function Rushee() { submitItem(); delay(750 + me.ping); + // unbug cursor + item = me.findItem(-1, 0, 3); + + if (item && item.toCursor()) { + Storage.Inventory.MoveTo(item); + } + return true; }; @@ -206,7 +228,8 @@ function Rushee() { break; } - Town.move("palace"); + Pather.usePortal(50, Config.Leader); + Pather.moveToExit(40, true); npc = getUnit(1, "jerhyn"); @@ -217,6 +240,8 @@ function Rushee() { } me.cancel(); + Pather.moveToExit(50, true); + Pather.usePortal(40, Config.Leader); Town.move("meshif"); npc = getUnit(1, "meshif"); @@ -323,14 +348,49 @@ function Rushee() { try { if (actions.length > 0) { switch (actions[0]) { - case "1": - print("command: 1"); + case "all in": + switch (leader.area) { + case 49: // Pick Book of Skill, use Book of Skill + Town.move("portalspot"); + Pather.usePortal(49, Config.Leader); + delay(500); + + while (true) { + target = getUnit(4, 552); + + if (!target) { + break; + } + + Pickit.pickItem(target); + delay(250); + + if (me.getItem(552)) { + print("Using book of skill"); + clickItem(1, me.getItem(552)); + + break; + } + } + Pather.usePortal(40, Config.Leader); + actions.shift(); + + break; + } + + actions.shift(); + + break; + case "1": while (!leader.area) { delay(500); } + //print(leader.area); + if (!Config.Rushee.Quester) { + //print("not a quester"); actions.shift(); break; @@ -357,6 +417,14 @@ function Rushee() { actions.shift(); + break; + case 49: + Town.move("portalspot"); + + if (Pather.usePortal(49, Config.Leader)) { + actions.shift(); + } + break; case 60: // Halls of the Dead level 3 Pather.usePortal(60, Config.Leader); @@ -431,54 +499,90 @@ function Rushee() { actions.shift(); break; - case 102: // Durance of Hate level 3 - if (me.area === 75) { - Pather.usePortal(102, Config.Leader); + case 94: // Ruined Temple + if (!Pather.usePortal(94, Config.Leader)) { + me.cancel(); + + break; } - if (me.area === 102) { - //this.checkQuestMonster(242); - while (leader.area === me.area) { - delay(500); - } + target = getUnit(2, 193); - if (me.mode === 17) { - me.revive(); + Misc.openChest(target); + delay(300); - while (!me.inTown) { - delay(500); - } + target = getUnit(4, 548); - Town.move("portalspot"); - Pather.usePortal(102, Config.Leader); - } + Pickit.pickItem(target); + Pather.usePortal(75, Config.Leader); + Town.move("alkor"); + + target = getUnit(1, "alkor"); + if (target && target.openMenu()) { + me.cancel(); + } + + Town.move("portalspot"); + actions.shift(); + + break; + case 102: // Durance of Hate level 3 + if (!Pather.usePortal(102, Config.Leader)) { + me.cancel(); + + break; + } + + actions.shift(); + + break; + case 104: // sometimes the portal can be in city of the damned... + case 105: + if (Pather.usePortal(null, Config.Leader)) { actions.shift(); } break; case 108: // Chaos Sanctuary Pather.usePortal(108, Config.Leader); + Pather.moveTo(7762, 5268); + Packet.flash(me.gid); + delay(500); + Pather.walkTo(7763, 5267, 2); while (!getUnit(1, 243)) { delay(500); } Pather.moveTo(7763, 5267); - this.checkQuestMonster(243); + actions.shift(); - if (me.gametype === 0) { - D2Bot.restart(); - } else { - if (me.mode === 17) { - me.revive(); + break; + case 110: // Bloody Foothils + Pather.usePortal(110, Config.Leader); + actions.shift(); - while (!me.inTown) { - delay(500); - } - } + break; + case 114: // Frozen River + Town.move("malah"); - Pather.usePortal(103, Config.Leader); + target = getUnit(1, "malah"); + + if (target && target.openMenu()) { + me.cancel(); + } + + Pather.usePortal(114, Config.Leader); + delay(500); + + target = getUnit(2, 558); + + if (target) { + Pather.moveToUnit(target); + sendPacket(1, 0x13, 4, 0x2, 4, target.gid); + delay(1000); + me.cancel(); } actions.shift(); @@ -493,31 +597,61 @@ function Rushee() { break; case "2": // Go back to town and check quest if (!Config.Rushee.Quester) { - actions.shift(); + switch (leader.area) { + // Non-questers can piggyback off quester out messages + case 110: // Shenk + if (me.act === 5) { + Town.move("larzuk"); - break; - } + target = getUnit(1, "larzuk"); - print("command: 2"); + if (target && target.openMenu()) { + me.cancel(); + } + } - // If dying, wait until animation is over - while (me.mode === 0) { - delay(40); - } + break; + case 114: // Anya + if (me.act === 5) { + Town.move("malah"); - // Revive if dead - if (me.mode === 17) { - me.revive(); + target = getUnit(1, "malah"); - // Wait until revive is complete - while (!me.inTown) { - delay(40); + if (target && target.openMenu()) { + me.cancel(); + } + + if (me.getItem(646)) { + print("Using scroll of resistance"); + clickItem(1, me.getItem(646)); + } + } + + break; + case 104: + case 105: + if (me.act === 4 && this.checkQuest(25, 1)) { + Town.move(NPC.Tyrael); + + target = getUnit(1, "tyrael"); + + if (target && target.openMenu()) { + me.cancel(); + } + } + + break; } + + actions.shift(); + + break; } switch (me.area) { - case 1: case 37: // Catacombs level 4 + this.revive(); + // Go to town if not there, break if procedure fails if (!me.inTown && !Pather.usePortal(1, Config.Leader)) { break; @@ -531,8 +665,19 @@ function Rushee() { actions.shift(); break; - case 40: + case 49: // Sewers 3 + this.revive(); + + if (!me.inTown && !Pather.usePortal(40, Config.Leader)) { + break; + } + + actions.shift(); + + break; case 74: // Arcane Sanctuary + this.revive(); + if (!me.inTown && !Pather.usePortal(40, Config.Leader)) { break; } @@ -556,8 +701,9 @@ function Rushee() { actions.shift(); break; - case 75: case 83: // Travincal + this.revive(); + if (!me.inTown && !Pather.usePortal(75, Config.Leader)) { break; } @@ -580,6 +726,103 @@ function Rushee() { Town.move("portalspot"); actions.shift(); + break; + case 102: // Durance 2 + this.revive(); + + if (!Pather.usePortal(75, Config.Leader)) { + break; + } + + actions.shift(); + + break; + case 104: + case 105: + this.revive(); + + if (!me.inTown && !Pather.usePortal(103, Config.Leader)) { + break; + } + + if (this.checkQuest(25, 1)) { + Town.move(NPC.Tyrael); + + target = getUnit(1, "tyrael"); + + if (target && target.openMenu()) { + me.cancel(); + } + + Town.move("portalspot"); + } + + actions.shift(); + + break; + case 108: // Chaos Sanctuary + this.revive(); + + if (me.gametype === 0) { + D2Bot.restart(); + + break; + } + + if (!me.inTown && !Pather.usePortal(103, Config.Leader)) { + break; + } + + actions.shift(); + + break; + case 110: // Bloody Foothils + this.revive(); + + if (!me.inTown && !Pather.usePortal(109, Config.Leader)) { + break; + } + + Town.move("larzuk"); + + target = getUnit(1, "larzuk"); + + if (target && target.openMenu()) { + me.cancel(); + } + + Town.move("portalspot"); + actions.shift(); + + break; + case 114: // Frozen River + this.revive(); + + if (!me.inTown && !Pather.usePortal(109, Config.Leader)) { + break; + } + + Town.move("malah"); + + target = getUnit(1, "malah"); + + if (target && target.openMenu()) { + me.cancel(); + } + + if (me.getItem(646)) { + print("Using Scroll of Resistance"); + clickItem(1, me.getItem(646)); + } + + Town.move("portalspot"); + actions.shift(); + + break; + default: + Town.move("portalspot"); + actions.shift(); + break; } @@ -641,6 +884,7 @@ function Rushee() { break; case "exit": + case "bye ~": D2Bot.restart(); break; @@ -656,13 +900,7 @@ function Rushee() { } me.cancel(); - - if (Config.Rushee.Quester) { - Town.move("portalspot"); - } else { - Town.move("palace"); - } - + Town.move("portalspot"); actions.shift(); break; @@ -692,6 +930,14 @@ function Rushee() { Town.move("portalspot"); actions.shift(); + break; + case me.name + " quest": + say("I am quester."); + + Config.Rushee.Quester = true; + + actions.shift(); + break; default: // Invalid command actions.shift(); diff --git a/d2bs/kolbot/libs/bots/Rusher.js b/d2bs/kolbot/libs/bots/Rusher.js index ef941571a..bf38b2f2b 100644 --- a/d2bs/kolbot/libs/bots/Rusher.js +++ b/d2bs/kolbot/libs/bots/Rusher.js @@ -1,7 +1,7 @@ /** * @filename Rusher.js * @author kolton -* @desc Rusher script. ALPHA VERSION +* @desc Rusher script. * Chat commands: * master - assigns player as master and listens to his commands * release - resets master @@ -18,8 +18,10 @@ function Rusher() { var i, rushThread, command, master, commandSplit0, commands = [], - sequence = ["andariel", "cube", "amulet", "staff", "summoner", "duriel", "travincal", "mephisto", "diablo", "ancients", "baal"]; - + sequence = [ + "andariel", "radament", "cube", "amulet", "staff", "summoner", "duriel", "lamesen", + "travincal", "mephisto", "izual", "diablo", "shenk", "anya", "ancients", "baal" + ]; rushThread = getScript("tools/rushthread.js"); this.reloadThread = function () { @@ -33,6 +35,8 @@ function Rusher() { load("tools/rushthread.js"); rushThread = getScript("tools/rushthread.js"); + + delay(500); }; this.getPlayerCount = function () { @@ -110,14 +114,14 @@ function Rusher() { case "quit": if (nick === master) { say("bye ~"); - quit(); + scriptBroadcast("quit"); } else { say("I'm only accepting commands from my master."); } break; default: - if (msg && msg.match(/^do \w|^clear \d/gi)) { + if (msg && msg.match(/^do \w|^clear \d|^pause$|^resume$/gi)) { if (nick === master) { commands.push(msg); } else { @@ -171,12 +175,16 @@ function Rusher() { switch (command) { case "pause": if (rushThread.running) { + say("Pausing"); + rushThread.pause(); } break; case "resume": if (!rushThread.running) { + say("Resuming"); + rushThread.resume(); } diff --git a/d2bs/kolbot/libs/bots/SealLeader.js b/d2bs/kolbot/libs/bots/SealLeader.js new file mode 100644 index 000000000..425806c90 --- /dev/null +++ b/d2bs/kolbot/libs/bots/SealLeader.js @@ -0,0 +1,279 @@ +function SealLeader() { + this.getLayout = function (seal, value) { + var sealPreset = getPresetUnit(108, 2, seal); + + if (!seal) { + throw new Error("Seal preset not found"); + } + + if (sealPreset.roomy * 5 + sealPreset.y === value || sealPreset.roomx * 5 + sealPreset.x === value) { + return 1; + } + + return 2; + }; + + this.initLayout = function () { + this.vizLayout = this.getLayout(396, 5275); + this.seisLayout = this.getLayout(394, 7773); + this.infLayout = this.getLayout(392, 7893); + }; + + this.getBoss = function (name) { + var i, boss, + glow = getUnit(2, 131); + + for (i = 0; i < 16; i += 1) { + boss = getUnit(1, name); + + if (boss) { + this.chaosPreattack(name, 8); + + return Attack.clear(40, 0, name); + } + + delay(250); + } + + return !!glow; + }; + + this.chaosPreattack = function (name, amount) { + var i, n, target, positions; + + switch (me.classid) { + case 0: + break; + case 1: + break; + case 2: + break; + case 3: + target = getUnit(1, name); + + if (!target) { + return; + } + + positions = [[6, 11], [0, 8], [8, -1], [-9, 2], [0, -11], [8, -8]]; + + for (i = 0; i < positions.length; i += 1) { + if (Attack.validSpot(target.x + positions[i][0], target.y + positions[i][1])) { // check if we can move there + Pather.moveTo(target.x + positions[i][0], target.y + positions[i][1]); + Skill.setSkill(Config.AttackSkill[2], 0); + + for (n = 0; n < amount; n += 1) { + Skill.cast(Config.AttackSkill[1], 1); + } + + break; + } + } + + break; + case 4: + break; + case 5: + break; + case 6: + break; + } + }; + + this.diabloPrep = function () { + var trapCheck, + tick = getTickCount(); + + while (getTickCount() - tick < 17500) { + if (getTickCount() - tick >= 8000) { + switch (me.classid) { + case 1: // Sorceress + if ([56, 59, 64].indexOf(Config.AttackSkill[1]) > -1) { + if (me.getState(121)) { + delay(500); + } else { + Skill.cast(Config.AttackSkill[1], 0, 7793, 5293); + } + + break; + } + + delay(500); + + break; + case 3: // Paladin + Skill.setSkill(Config.AttackSkill[2]); + Skill.cast(Config.AttackSkill[1], 1); + + break; + case 5: // Druid + if (Config.AttackSkill[1] === 245) { + Skill.cast(Config.AttackSkill[1], 0, 7793, 5293); + + break; + } + + delay(500); + + break; + case 6: // Assassin + if (Config.UseTraps) { + trapCheck = ClassAttack.checkTraps({x: 7793, y: 5293}); + + if (trapCheck) { + ClassAttack.placeTraps({x: 7793, y: 5293, classid: 243}, trapCheck); + + break; + } + } + + delay(500); + + break; + default: + delay(500); + } + } else { + delay(500); + } + + if (getUnit(1, 243)) { + return true; + } + } + + throw new Error("Diablo not found"); + }; + + this.openSeal = function (classid) { + var i, j, seal; + + for (i = 0; i < 5; i += 1) { + Pather.moveToPreset(108, 2, classid, classid === 394 ? 5 : 2, classid === 394 ? 5 : 0); + + if (i > 1) { + Attack.clear(10); + } + + for (j = 0; j < 3; j += 1) { + seal = getUnit(2, classid); + + if (seal) { + break; + } + + delay(100); + } + + if (!seal) { + throw new Error("Seal not found (id " + classid + ")"); + } + + if (seal.mode) { + return true; + } + + sendPacket(1, 0x13, 4, 0x2, 4, seal.gid); + delay(classid === 394 ? 1000 : 500); + + if (!seal.mode) { + if (classid === 394 && Attack.validSpot(seal.x + 15, seal.y)) { // de seis optimization + Pather.moveTo(seal.x + 15, seal.y); + } else { + Pather.moveTo(seal.x - 5, seal.y - 5); + } + + delay(500); + } else { + return true; + } + } + + throw new Error("Failed to open seal (id " + classid + ")"); + }; + + // START + Town.doChores(); + Pather.useWaypoint(107); + Precast.doPrecast(true); + this.initLayout(); + + if (this.vizLayout === 1) { + Pather.moveTo(7708, 5269); + } else { + Pather.moveTo(7647, 5267); + } + + Attack.securePosition(me.x, me.y, 35, 3000, true); + Pather.makePortal(); + say("in"); + this.openSeal(395); + this.openSeal(396); + + if (this.vizLayout === 1) { + Pather.moveTo(7691, 5292); + } else { + Pather.moveTo(7695, 5316); + } + + // Kill Viz + if (!this.getBoss(getLocaleString(2851))) { + throw new Error("Failed to kill Vizier"); + } + + say("out"); + + if (this.seisLayout === 1) { + Pather.moveTo(7767, 5147); + } else { + Pather.moveTo(7820, 5147); + } + + Attack.securePosition(me.x, me.y, 35, 3000, true); + Pather.makePortal(); + say("in"); + this.openSeal(394); + + if (this.seisLayout === 1) { + Pather.moveTo(7771, 5196); + } else { + Pather.moveTo(7798, 5186); + } + + if (!this.getBoss(getLocaleString(2852))) { + throw new Error("Failed to kill de Seis"); + } + + say("out"); + + if (this.infLayout === 1) { + Pather.moveTo(7860, 5314); + } else { + Pather.moveTo(7909, 5317); + } + + Attack.securePosition(me.x, me.y, 35, 3000, true); + Pather.makePortal(); + say("in"); + this.openSeal(392); + + if (this.infLayout === 2) { + Pather.moveTo(7928, 5295); + } + + if (!this.getBoss(getLocaleString(2853))) { + throw new Error("Failed to kill Infector"); + } + + this.openSeal(393); + say("out"); + Pather.moveTo(7763, 5267); + Pather.makePortal(); + Pather.moveTo(7788, 5292); + say("in"); + this.diabloPrep(); + Attack.kill(243); // Diablo + Pickit.pickItems(); + + return true; +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/SealLeecher.js b/d2bs/kolbot/libs/bots/SealLeecher.js new file mode 100644 index 000000000..b93a3baab --- /dev/null +++ b/d2bs/kolbot/libs/bots/SealLeecher.js @@ -0,0 +1,84 @@ +function SealLeecher() { + var monster, + commands = []; + + Town.goToTown(4); + Town.doChores(); + Town.move("portalspot"); + + if (!Config.Leader) { + D2Bot.printToConsole("You have to set Config.Leader"); + D2Bot.stop(); + + return false; + } + + addEventListener("chatmsg", + function (nick, msg) { + if (nick === Config.Leader) { + commands.push(msg); + } + }); + + // Wait until leader is partied + while (!Misc.inMyParty(Config.Leader)) { + delay(1000); + } + + while (Misc.inMyParty(Config.Leader)) { + if (commands.length > 0) { + switch (commands[0]) { + case "in": + if (me.inTown) { + Pather.usePortal(108, Config.Leader); + delay(250); + } + + if (getDistance(me, 7761, 5267) < 10) { + Pather.walkTo(7761, 5267, 2); + } + + commands.shift(); + + break; + case "out": + if (!me.inTown) { + Pather.usePortal(103, Config.Leader); + } + + commands.shift(); + + break; + } + } + + while (me.mode === 40) { + delay(40); + } + + if (me.mode === 17) { + me.revive(); + + while (!me.inTown) { + delay(40); + } + } + + if (!me.inTown) { + monster = getUnit(1); + + if (monster) { + do { + if (Attack.checkMonster(monster) && getDistance(me, monster) < 20) { + me.overhead("HOT"); + Pather.usePortal(103, Config.Leader); + } + } while (monster.getNext()); + } + } + + delay(100); + } + + return true; +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/ShopBot.js b/d2bs/kolbot/libs/bots/ShopBot.js index b02acae1f..2b64af2cf 100644 --- a/d2bs/kolbot/libs/bots/ShopBot.js +++ b/d2bs/kolbot/libs/bots/ShopBot.js @@ -1,5 +1,5 @@ function ShopBot() { - var npc, tickCount, town, wpArea, path, menuId, + var i, tickCount, cycles = 0, cyclesText = new Text("Cycles in last minute:", 50, 260, 2, 1), title = new Text("kolbot shopbot", 50, 245, 2, 1), @@ -8,13 +8,85 @@ function ShopBot() { validItems = 0, leadRetry = 10, totalCycles = 0, - leadTimeout = 30; // NPC move timeout in seconds + leadTimeout = 20; // NPC move timeout in seconds + + this.pickEntries = []; + this.npcs = {}; + this.paths = {}; + + this.buildPickList = function () { + var i, nipfile, line, lines, info, + filepath = "pickit/shopbot.nip", + filename = filepath.substring(filepath.lastIndexOf("/") + 1, filepath.length); + + if (!FileTools.exists(filepath)) { + Misc.errorReport("ÿc1NIP file doesn't exist: ÿc0" + filepath); + + return false; + } + + try { + nipfile = File.open(filepath, 0); + } catch (fileError) { + Misc.errorReport("ÿc1Failed to load NIP: ÿc0" + filename); + } + + if (!nipfile) { + return false; + } + + lines = nipfile.readAllLines(); + + nipfile.close(); + + for (i = 0; i < lines.length; i += 1) { + info = { + line: i + 1, + file: filename, + string: lines[i] + }; + + line = NTIP.ParseLineInt(lines[i], info); + + if (line) { + this.pickEntries.push(line); + } + } + + return true; + }; + + this.processPath = function (npc, path) { + var i, + cutIndex = 0, + dist = 100; + + for (i = 0; i < path.length; i += 2) { + if (getDistance(npc, path[i], path[i + 1]) < dist) { + cutIndex = i; + dist = getDistance(npc, path[i], path[i + 1]); + } + } + + return path.slice(cutIndex); + }; this.mover = function (npc, path) { var i, j; + path = this.processPath(npc, path); + + if (path.length === 2 && getDistance(npc.x, npc.y, path[0], path[1]) < 4) { + return true; + } + for (i = 0; i < path.length; i += 2) { - Pather.moveTo(path[i] - 3, path[i + 1] - 3); + if (i === path.length - 2) { + Pather.moveTo(path[i] - 3, path[i + 1] - 3); + } else { + Pather.moveTo(path[i], path[i + 1]); + } + moveNPC(npc, path[i], path[i + 1]); for (j = 0; j < leadTimeout; j += 1) { @@ -22,7 +94,7 @@ function ShopBot() { delay(100); } - if (getDistance(npc.x, npc.y, path[i], path[i + 1]) < 4) { + if (getDistance(me, npc) < (i === path.length - 2 ? 8 : 5)) { break; } @@ -48,51 +120,59 @@ function ShopBot() { throw new Error("Unit.openMenu: Must be used on NPCs."); } + var i, tick, + interactedNPC = getInteractedNPC(); + + if (interactedNPC && interactedNPC.name !== npc.name) { + sendPacket(1, 0x30, 4, interactedNPC.type, 4, interactedNPC.gid); + me.cancel(); + } + if (getUIFlag(0x08)) { return true; } - var i, j; - - for (i = 0; i < 3; i += 1) { + for (i = 0; i < 10; i += 1) { if (getDistance(me.x, me.y, npc.x, npc.y) > 5) { Pather.walkTo(npc.x, npc.y); } - //npc.interact(); - sendPacket(1, 0x13, 4, 1, 4, npc.gid); + if (!getUIFlag(0x08)) { + sendPacket(1, 0x13, 4, 1, 4, npc.gid); + sendPacket(1, 0x2f, 4, 1, 4, npc.gid); + } - for (j = 0; j < 20; j += 1) { - if (j % 4 === 0) { - me.cancel(); - delay(300); - //npc.interact(); - sendPacket(1, 0x13, 4, 1, 4, npc.gid); - } + tick = getTickCount(); + while (getTickCount() - tick < Math.max(Math.round((i + 1) * 250 / (i / 3 + 1)), me.ping + 1)) { if (getUIFlag(0x08)) { + //print("openMenu try: " + i); + return true; } - delay(50); + delay(10); } } - D2Bot.printToConsole("Failed to open NPC menu"); + me.cancel(); return false; }; - this.shopItems = function (npc) { - var i, item, - items = []; + this.shopItems = function (npc, menuId) { + var i, item, items, bought; - if (!npc) { - return false; + if (!Storage.Inventory.CanFit({sizex: 2, sizey: 4}) && AutoMule.getMuleItems().length > 0) { + D2Bot.printToConsole("Mule triggered"); + scriptBroadcast("mule"); + scriptBroadcast("quit"); + + return true; } - while (me.ping > 700) { - delay(100); + if (!npc) { + return false; } for (i = 0; i < 10; i += 1) { @@ -115,40 +195,57 @@ function ShopBot() { return false; } - me.overhead(npc.itemcount + " items"); + items = []; do { - if (Config.ShopBot.ScanIDs.length === 0 || Config.ShopBot.ScanIDs.indexOf(item.classid) > -1) { + if (Config.ShopBot.ScanIDs.indexOf(item.classid) > -1 || Config.ShopBot.ScanIDs.length === 0) { items.push(copyUnit(item)); } } while (item.getNext()); + me.overhead(npc.itemcount + " items, " + items.length + " valid"); + validItems += items.length; - frequency.text = "Valid item frequency: " + ((validItems * 100 / totalCycles).toFixed(2).toString()) + " %"; + frequency.text = "Valid base items / cycle: " + ((validItems / totalCycles).toFixed(2).toString()); for (i = 0; i < items.length; i += 1) { - //print("Scanning " + items[i].name); - - if (Storage.Inventory.CanFit(items[i]) && - Pickit.canPick(items[i]) && - me.getStat(14) + me.getStat(15) >= items[i].getItemCost(0) && - Pickit.checkItem(items[i]).result === 1 + if (Storage.Inventory.CanFit(items[i]) && Pickit.canPick(items[i]) && + me.gold >= items[i].getItemCost(0) && + NTIP.CheckItem(items[i], this.pickEntries) ) { + beep(); D2Bot.printToConsole("Match found!", 7); delay(1000); if (npc.startTrade(menuId)) { Misc.logItem("Shopped", items[i]); items[i].buy(); + + bought = true; + } + + if (Config.ShopBot.QuitOnMatch) { + scriptBroadcast("quit"); } } } + if (bought) { + me.cancel(); + Town.stash(); + } + return true; }; this.useWp = function (area) { - var i, unit; + if (totalCycles === 0) { + me.cancel(); + + return Pather.useWaypoint(area, true); + } + + var i, tick, unit, interactedNPC; if (me.area === area) { return true; @@ -161,132 +258,379 @@ function ShopBot() { } if (getUIFlag(0x08)) { + interactedNPC = getInteractedNPC(); + + if (interactedNPC) { + sendPacket(1, 0x30, 4, interactedNPC.type, 4, interactedNPC.gid); + } + me.cancel(); } - for (i = 0; i < 80; i += 1) { - if (i % 20 === 0) { - if (getDistance(me.x, me.y, unit.x, unit.y) > 5) { - Pather.walkTo(unit.x, unit.y); + for (i = 0; i < 10; i += 1) { + if (me.area === unit.area && getDistance(me, unit) > 5) { + Pather.walkTo(unit.x, unit.y); + } + + unit.interact(area); + + tick = getTickCount(); + + while (getTickCount() - tick < Math.max(Math.round((i + 1) * 250 / (i / 3 + 1)), me.ping + 1)) { + if (me.area === area) { + return true; } - unit.interact(area); + delay(10); } + } + + return false; + }; - delay(75); + this.shopAtNPC = function (name) { + var i, path, npc, menuId, wp, temp; - while (!me.area || !me.gameReady) { - delay(20); + switch (name) { + case "akara": + case "charsi": + if (me.inTown) { + if (!Town.goToTown(1)) { + break; + } + } else { + if (!this.useWp(1)) { + break; + } } - if (me.area === area) { - return true; + npc = this.npcs[name] || getUnit(1, name); + + if (!npc) { + Town.move(name); + + npc = getUnit(1, name); } - } - print("Failed to use WP"); + if (!npc) { + Town.move("waypoint"); - return false; - }; + npc = getUnit(1, name); + } - Town.doChores(); + if (!npc) { + break; + } - switch (Config.ShopBot.ShopNPC.toLowerCase()) { - case "fara": - wpArea = 48; - town = 40; - path = [5112, 5094, 5092, 5096, 5078, 5098, 5070, 5085]; - menuId = "Repair"; + if (!this.npcs[name]) { + this.npcs[name] = copyUnit(npc); + } - if (!Town.goToTown(2) || !Town.move(NPC.Fara)) { - throw new Error("Failed to get to NPC"); - } + if (!this.paths[name]) { + if (!getUnit(2, "waypoint")) { + Town.move("waypoint"); + } - npc = getUnit(1, NPC.Fara); + wp = getUnit(2, "waypoint"); + wp = {x: wp.x, y: wp.y}; - break; - case "elzix": - wpArea = 48; - town = 40; - path = [5038, 5099, 5059, 5102, 5068, 5090, 5067, 5086]; - menuId = "Shop"; + Town.move(name); - if (!Town.goToTown(2) || !Town.move(NPC.Elzix)) { - throw new Error("Failed to get to NPC"); - } + path = getPath(me.area, npc.x, npc.y, wp.x + 2, wp.y + 2, 0, 8); + this.paths[name] = []; - npc = getUnit(1, NPC.Elzix); + for (i = 0; i < path.length; i += 1) { + temp = Pather.getNearestWalkable(path[i].x, path[i].y, 5, 1, 0x1 | 0x400, 4); - break; - case "drognan": - wpArea = 48; - town = 40; - path = [5093, 5049, 5088, 5060, 5093, 5079, 5078, 5087, 5070, 5085]; - menuId = "Shop"; + if (temp) { + this.paths[name] = this.paths[name].concat(temp); + } else { + this.paths[name].push(path[i].x); + this.paths[name].push(path[i].y); + } + } + } - if (!Town.goToTown(2) || !Town.move(NPC.Drognan)) { - throw new Error("Failed to get to NPC"); - } + path = this.paths[name]; + menuId = "Shop"; - npc = getUnit(1, NPC.Drognan); + break; + case "elzix": + if (me.inTown) { + if (!Town.goToTown(2)) { + break; + } + } else { + if (!this.useWp(40)) { + break; + } + } - break; - case "ormus": - wpArea = 101; - town = 75; - path = [5147, 5089, 5156, 5075, 5157, 5063, 5160, 5050]; - menuId = "Shop"; + npc = this.npcs[name] || getUnit(1, NPC.Elzix); - if (!Town.goToTown(3) || !Town.move(NPC.Ormus)) { - throw new Error("Failed to get to NPC"); - } + if (!npc) { + Town.move(NPC.Elzix); + + npc = getUnit(1, NPC.Elzix); + } + + if (!npc) { + Town.move("waypoint"); + + npc = getUnit(1, NPC.Elzix); + } - npc = getUnit(1, NPC.Ormus); + if (!npc) { + break; + } + + if (!this.npcs[name]) { + this.npcs[name] = copyUnit(npc); + } - break; - case "anya": - wpArea = 129; - town = 109; - path = [5122, 5119, 5129, 5105, 5123, 5087, 5115, 5068]; - menuId = "Shop"; + path = [5038, 5099, 5059, 5102, 5068, 5090, 5067, 5086]; + menuId = "Shop"; + + break; + case "fara": + if (me.inTown) { + if (!Town.goToTown(2)) { + break; + } + } else { + if (!this.useWp(40)) { + break; + } + } - if (!Town.goToTown(5) || !Town.move(NPC.Anya)) { - throw new Error("Failed to get to NPC"); + npc = this.npcs[name] || getUnit(1, NPC.Fara); + + if (!npc) { + Town.move(NPC.Fara); + + npc = getUnit(1, NPC.Fara); + } + + if (!npc) { + Town.move("waypoint"); + + npc = getUnit(1, NPC.Fara); + } + + if (!npc) { + break; + } + + if (!this.npcs[name]) { + this.npcs[name] = copyUnit(npc); + } + + path = [5112, 5094, 5092, 5096, 5078, 5098, 5070, 5085]; + menuId = "Repair"; + + break; + case "drognan": + if (me.inTown) { + if (!Town.goToTown(2)) { + break; + } + } else { + if (!this.useWp(40)) { + break; + } + } + + npc = this.npcs[name] || getUnit(1, NPC.Drognan); + + if (!npc) { + Town.move(NPC.Drognan); + + npc = getUnit(1, NPC.Drognan); + } + + if (!npc) { + Town.move("waypoint"); + + npc = getUnit(1, NPC.Drognan); + } + + if (!npc) { + break; + } + + if (!this.npcs[name]) { + this.npcs[name] = copyUnit(npc); + } + + path = [5093, 5049, 5088, 5060, 5093, 5079, 5078, 5087, 5070, 5085]; + menuId = "Shop"; + + break; + case "ormus": + if (me.inTown) { + if (!Town.goToTown(3)) { + break; + } + } else { + if (!this.useWp(75)) { + break; + } + } + + npc = this.npcs[name] || getUnit(1, NPC.Ormus); + + if (!npc) { + Town.move(NPC.Ormus); + + npc = getUnit(1, NPC.Ormus); + } + + if (!npc) { + Town.move("waypoint"); + + npc = getUnit(1, NPC.Ormus); + } + + if (!npc) { + break; + } + + if (!this.npcs[name]) { + this.npcs[name] = copyUnit(npc); + } + + path = [5135, 5093, 5147, 5089, 5156, 5075, 5157, 5063, 5160, 5050]; + menuId = "Shop"; + + break; + case "asheara": + if (me.inTown) { + if (!Town.goToTown(3)) { + break; + } + } else { + if (!this.useWp(75)) { + break; + } + } + + npc = this.npcs[name] || getUnit(1, NPC.Asheara); + + if (!npc) { + Town.move(NPC.Asheara); + + npc = getUnit(1, NPC.Asheara); + } + + if (!npc) { + Town.move("waypoint"); + + npc = getUnit(1, NPC.Asheara); + } + + if (!npc) { + break; + } + + if (!this.npcs[name]) { + this.npcs[name] = copyUnit(npc); + } + + path = [5049, 5093, 5067, 5092, 5084, 5093, 5110, 5093, 5132, 5093, 5147, 5086, 5154, 5070, 5160, 5049]; + menuId = "Shop"; + + break; + case "anya": + if (me.inTown) { + if (!Town.goToTown(5)) { + break; + } + } else { + if (!this.useWp(109)) { + break; + } + } + + npc = this.npcs[name] || getUnit(1, NPC.Anya); + + if (!npc) { + Town.move(NPC.Anya); + + npc = getUnit(1, NPC.Anya); + } + + if (!npc) { + Town.move("waypoint"); + + npc = getUnit(1, NPC.Anya); + } + + if (!npc) { + break; + } + + if (!this.npcs[name]) { + this.npcs[name] = copyUnit(npc); + } + + path = [5122, 5119, 5129, 5105, 5123, 5087, 5115, 5070]; + menuId = "Shop"; + + break; + default: + throw new Error("Invalid NPC"); } - npc = getUnit(1, NPC.Anya); + if (npc) { + if (!this.mover(npc, path)) { + return false; + } - break; - case "malah": - wpArea = 113; - town = 109; - path = [5077, 5032, 5089, 5025, 5100, 5021, 5106, 5051, 5116, 5071]; - menuId = "Shop"; + if (Config.ShopBot.CycleDelay) { + delay(Config.ShopBot.CycleDelay); + } - if (!Town.goToTown(5) || !Town.move(NPC.Malah)) { - throw new Error("Failed to get to NPC"); + if (this.openMenu(npc)) { + this.shopItems(npc, menuId); + } } - npc = getUnit(1, NPC.Malah); + return true; + }; + + // START + for (i = 0; i < Config.ShopBot.ScanIDs.length; i += 1) { + if (isNaN(Config.ShopBot.ScanIDs[i])) { + if (NTIPAliasClassID.hasOwnProperty(Config.ShopBot.ScanIDs[i].replace(/\s+/g, "").toLowerCase())) { + Config.ShopBot.ScanIDs[i] = NTIPAliasClassID[Config.ShopBot.ScanIDs[i].replace(/\s+/g, "").toLowerCase()]; + } else { + Misc.errorReport("ÿc1Invalid ShopBot entry:ÿc0 " + Config.ShopBot.ScanIDs[i]); + Config.ShopBot.ScanIDs.splice(i, 1); - break; - default: - throw new Error("Invalid shopbot NPC."); + i -= 1; + } + } } - if (!npc) { - throw new Error("Failed to find NPC."); + if (typeof Config.ShopBot.ShopNPC === "string") { + Config.ShopBot.ShopNPC = [Config.ShopBot.ShopNPC]; } - if (!this.mover(npc, path)) { - throw new Error("Failed to move NPC"); + for (i = 0; i < Config.ShopBot.ShopNPC.length; i += 1) { + Config.ShopBot.ShopNPC[i] = Config.ShopBot.ShopNPC[i].toLowerCase(); } - Town.move("waypoint"); + if (Config.ShopBot.MinGold && me.getStat(14) + me.getStat(15) < Config.ShopBot.MinGold) { + return true; + } + + this.buildPickList(); + print("Shopbot: Pickit entries: " + this.pickEntries.length); + Town.doChores(); tickCount = getTickCount(); - while (true) { + while (!Config.ShopBot.Cycles || totalCycles < Config.ShopBot.Cycles) { if (getTickCount() - tickCount >= 60 * 1000) { cyclesText.text = "Cycles in last minute: " + cycles.toString(); totalCyclesText.text = "Total cycles: " + totalCycles.toString(); @@ -294,34 +638,16 @@ function ShopBot() { tickCount = getTickCount(); } - if (me.area === town) { - if (copyUnit(npc).x === undefined) { - throw new Error("NPC unit reference lost"); - } - - if (this.openMenu(npc)) { - this.shopItems(npc); - } - - me.cancel(); - } - - if (me.area === town) { - if (totalCycles === 0) { - Pather.useWaypoint(wpArea, true); - } else { - this.useWp(wpArea); - } + for (i = 0; i < Config.ShopBot.ShopNPC.length; i += 1) { + this.shopAtNPC(Config.ShopBot.ShopNPC[i]); } - if (me.area === wpArea) { - this.useWp(town); + if (me.inTown) { + this.useWp([35, 48, 101, 107, 113][me.act - 1]); } cycles += 1; totalCycles += 1; - - delay(5); } return true; diff --git a/d2bs/kolbot/libs/bots/Tristram.js b/d2bs/kolbot/libs/bots/Tristram.js index f717d231b..fd4bdaedd 100644 --- a/d2bs/kolbot/libs/bots/Tristram.js +++ b/d2bs/kolbot/libs/bots/Tristram.js @@ -1,15 +1,42 @@ /** * @filename Tristram.js -* @author kolton +* @author kolton, cuss * @desc clear Tristram */ function Tristram() { - if (!me.getQuest(4, 3)) { - throw new Error("You don't have the Cain quest"); - } + var tree, scroll, akara, stones, gibbet; + + if (!me.getQuest(4, 4) && !me.getItem(525)) { + if (!me.getItem(524)) { + // print("We need Scroll of Inifuss"); + Town.doChores(); + Pather.useWaypoint(5); + Precast.doPrecast(true); + + if (!Pather.moveToPreset(me.area, 2, 30, 5, 5)) { + throw new Error("Failed to move to Tree of Inifuss"); + } + + tree = getUnit(2, 30); - var i; + Misc.openChest(tree); + delay(300); + + scroll = getUnit(4, 524); + + Pickit.pickItem(scroll); + Town.goToTown(); + } + + // print("We need Key to the Cairn Stones"); + Town.move("akara"); + + akara = getUnit(1, "akara"); + + akara.openMenu(); + me.cancel(); + } Town.doChores(); Pather.useWaypoint(4); @@ -19,19 +46,43 @@ function Tristram() { throw new Error("Failed to move to Rakanishu"); } + if (!me.getQuest(4, 4)) { + stones = [getUnit(2, 17), getUnit(2, 18), getUnit(2, 19), getUnit(2, 20), getUnit(2, 21)]; + } + Attack.clear(15, 0, getLocaleString(2872)); // Rakanishu - for (i = 0; i < 5; i += 1) { - if (Pather.usePortal(38)) { - break; - } + while (!me.getQuest(4, 4)) { + stones.forEach(function (stone) { + if (!stone.mode) { + Attack.securePosition(stone.x, stone.y, 10, me.ping * 2); + Misc.click(0, 0, stone); + } + }); + } - delay(1000); + while (!Pather.usePortal(38)) { + Attack.securePosition(me.x, me.y, 10, 1000); } + Pather.moveTo(me.x, me.y + 6); + if (Config.Tristram.PortalLeech) { Pather.makePortal(); delay(1000); + } + + gibbet = getUnit(2, 26); + + if (!gibbet.mode) { + if (!Pather.moveToPreset(me.area, 2, 26, 0, 0, true, true)) { + throw new Error("Failed to move to Cain's Gibbet"); + } + + Misc.openChest(gibbet); + } + + if (Config.Tristram.PortalLeech) { Attack.clearLevel(0); } else { Attack.clearLevel(Config.ClearType); diff --git a/d2bs/kolbot/libs/bots/Wakka.js b/d2bs/kolbot/libs/bots/Wakka.js index a85874412..8f29ea91c 100644 --- a/d2bs/kolbot/libs/bots/Wakka.js +++ b/d2bs/kolbot/libs/bots/Wakka.js @@ -8,7 +8,8 @@ var stopLvl = 99; function Wakka() { var i, safeTP, portal, vizClear, seisClear, infClear, tick, diablo, - minDist = 40, + timeout = 1, // minutes + minDist = 50, maxDist = 80, leaderUnit = null, leaderPartyUnit = null, @@ -44,6 +45,10 @@ function Wakka() { } delay(500); + + if (getTickCount() - me.gamestarttime >= timeout * 6e4) { + throw new Error("No leader found"); + } } while (!leader); // repeat until leader is found (or until game is empty) return false; @@ -161,7 +166,7 @@ function Wakka() { }; this.followPath = function (dest) { - var path = getPath(me.area, me.x, me.y, dest[0], dest[1], 0, 15); + var path = getPath(me.area, me.x, me.y, dest[0], dest[1], 0, 10); if (!path) { throw new Error("Failed go get path"); @@ -216,7 +221,7 @@ function Wakka() { } } - if (Pather.walkTo(path[0].x, path[0].y)) { + if (Pather.moveTo(path[0].x, path[0].y)) { path.shift(); } @@ -228,7 +233,6 @@ function Wakka() { // start Town.goToTown(4); - Town.doChores(); Town.move("portalspot"); if (Config.Leader) { @@ -247,7 +251,10 @@ function Wakka() { } } - if (leader || autoLeaderDetect(108)) { + autoLeaderDetect(108); + Town.doChores(); + + if (leader) { while (Misc.inMyParty(leader)) { if (me.getStat(12) >= stopLvl) { D2Bot.stop(); @@ -255,14 +262,16 @@ function Wakka() { switch (me.area) { case 103: - portal = Pather.getPortal(108, leader); + //portal = Pather.getPortal(108, leader); + portal = Pather.getPortal(108, null); if (portal) { if (!safeTP) { delay(5000); } - Pather.usePortal(108, leader); + //Pather.usePortal(108, leader); + Pather.usePortal(108, null); } break; @@ -270,7 +279,8 @@ function Wakka() { if (!safeTP) { if (this.checkMonsters(25, false)) { me.overhead("hot tp"); - Pather.usePortal(103, leader); + //Pather.usePortal(103, leader); + Pather.usePortal(103, null); this.getCorpse(); break; diff --git a/d2bs/kolbot/libs/common/Attack.js b/d2bs/kolbot/libs/common/Attack.js index 2baa8fbba..148cfee77 100644 --- a/d2bs/kolbot/libs/common/Attack.js +++ b/d2bs/kolbot/libs/common/Attack.js @@ -16,8 +16,6 @@ var Attack = { include("common/Attacks/" + this.classes[me.classid] + ".js"); } - ClassAttack.init(); - if (Config.AttackSkill[1] < 0 || Config.AttackSkill[3] < 0) { showConsole(); print("ÿc1Bad attack config. Don't expect your bot to attack."); @@ -29,6 +27,23 @@ var Attack = { } }, + getCustomAttack: function (unit) { + var i; + + // Check if unit got invalidated + if (!unit || !unit.name || !copyUnit(unit).x) { + return false; + } + + for (i in Config.CustomAttack) { + if (Config.CustomAttack.hasOwnProperty(i) && unit.name.toLowerCase() === i.toLowerCase()) { + return Config.CustomAttack[i]; + } + } + + return false; + }, + // Get items with charges getCharges: function () { if (!Skill.charges) { @@ -150,13 +165,14 @@ var Attack = { } while (attackCount < 300 && this.checkMonster(target) && this.skipCheck(target)) { - // Get the target again if the bot went to town and back - if (Misc.townCheck()) { - target = getUnit(1, -1, -1, gid); - } + Misc.townCheck(); if (!target || !copyUnit(target).x) { // Check if unit got invalidated, happens if necro raises a skeleton from the boss's corpse. - break; + target = getUnit(1, -1, -1, gid); + + if (!target) { + break; + } } if (Config.Dodge && me.hp * 100 / me.hpmax <= Config.DodgeHP) { @@ -167,7 +183,11 @@ var Attack = { Precast.weaponSwitch(Math.abs(Config.MFSwitch)); } - if (ClassAttack.doAttack(target, attackCount % 15 === 0) < 2) { + if (attackCount > 0 && attackCount % 15 === 0 && Skill.getRange(Config.AttackSkill[1]) < 4) { + Packet.flash(me.gid); + } + + if (!ClassAttack.doAttack(target, attackCount % 15 === 0)) { errorInfo = " (doAttack failed)"; break; @@ -197,6 +217,39 @@ var Attack = { return true; }, + hurt: function (classId, percent) { + var i, target, + attackCount = 0; + + for (i = 0; i < 5; i += 1) { + target = getUnit(1, classId); + + if (target) { + break; + } + + delay(200); + } + + while (attackCount < 300 && Attack.checkMonster(target) && Attack.skipCheck(target)) { + if (!ClassAttack.doAttack(target, attackCount % 15 === 0)) { + break; + } + + if (!copyUnit(target).x) { + return true; + } + + attackCount += 1; + + if (target.hp * 100 / 128 <= percent) { + break; + } + } + + return true; + }, + getScarinessLevel: function (unit) { var scariness = 0, ids = [58, 59, 60, 61, 62, 101, 102, 103, 104, 105, 278, 279, 280, 281, 282, 298, 299, 300, 645, 646, 647, 662, 663, 664, 667, 668, 669, 670, 675, 676]; @@ -277,7 +330,7 @@ var Attack = { if (bossId) { for (i = 0; !boss && i < 5; i += 1) { - boss = getUnit(1, bossId); + boss = bossId > 999 ? getUnit(1, -1, -1, bossId) : getUnit(1, bossId); delay(200); } @@ -310,11 +363,7 @@ var Attack = { } while (target.getNext()); } - if (!start) { - return true; - } - - while (monsterList.length > 0 && attackCount < 300) { + while (start && monsterList.length > 0 && attackCount < 300) { if (boss) { orgx = boss.x; orgy = boss.y; @@ -339,41 +388,52 @@ var Attack = { result = ClassAttack.doAttack(target, attackCount % 15 === 0); - switch (result) { - case 1: - monsterList.shift(); - - break; - case 2: - case 3: - if (!(target.spectype & 0x7) && me.area !== 131) { - for (i = 0; i < gidAttack.length; i += 1) { - if (gidAttack[i].gid === target.gid) { - break; - } + if (result) { + for (i = 0; i < gidAttack.length; i += 1) { + if (gidAttack[i].gid === target.gid) { + break; } + } - if (i === gidAttack.length) { - gidAttack.push({gid: target.gid, attacks: 0}); - } + if (i === gidAttack.length) { + gidAttack.push({gid: target.gid, attacks: 0, name: target.name}); + } + + gidAttack[i].attacks += 1; + attackCount += 1; - gidAttack[i].attacks += 1; + // Desync/bad position handler + switch (Config.AttackSkill[(target.spectype & 0x7) ? 1 : 3]) { + case 112: + //print(gidAttack[i].name + " " + gidAttack[i].attacks); - if (gidAttack[i].attacks > 15) { - print("ÿc1Skipping " + target.name + " " + target.gid + " " + gidAttack[i].attacks); - monsterList.shift(); + // Tele in random direction with Blessed Hammer + if (gidAttack[i].attacks > 0 && gidAttack[i].attacks % ((target.spectype & 0x7) ? 4 : 2) === 0) { + //print("random move m8"); + Pather.moveTo(me.x + rand(-1, 1) * 5, me.y + rand(-1, 1) * 5); } + + break; + default: + // Flash with melee skills + if (gidAttack[i].attacks > 0 && gidAttack[i].attacks % ((target.spectype & 0x7) ? 15 : 5) === 0 && Skill.getRange(Config.AttackSkill[(target.spectype & 0x7) ? 1 : 3]) < 4) { + Packet.flash(me.gid); + } + + break; } - attackCount += 1; + // Skip non-unique monsters after 15 attacks, except in Throne of Destruction + if (me.area !== 131 && !(target.spectype & 0x7) && gidAttack[i].attacks > 15) { + print("ÿc1Skipping " + target.name + " " + target.gid + " " + gidAttack[i].attacks); + monsterList.shift(); + } if (target.mode === 0 || target.mode === 12 || Config.FastPick === 2) { Pickit.fastPick(); } - - break; - default: - return false; + } else { + monsterList.shift(); } } else { monsterList.shift(); @@ -381,7 +441,7 @@ var Attack = { } ClassAttack.afterAttack(pickit); - this.openChests(range); + this.openChests(range, orgx, orgy); if (attackCount > 0 && pickit) { Pickit.pickItems(); @@ -391,10 +451,18 @@ var Attack = { }, // Filter monsters based on classId, spectype and range - getMob: function (classid, spectype, range) { + getMob: function (classid, spectype, range, center) { var monsterList = [], monster = getUnit(1); + if (range === undefined) { + range = 25; + } + + if (!center) { + center = me; + } + switch (typeof classid) { case "number": case "string": @@ -402,7 +470,7 @@ var Attack = { if (monster) { do { - if (getDistance(me, monster) <= range && (!spectype || (monster.spectype & spectype)) && this.checkMonster(monster)) { + if (getDistance(center.x, center.y, monster.x, monster.y) <= range && (!spectype || (monster.spectype & spectype)) && this.checkMonster(monster)) { monsterList.push(copyUnit(monster)); } } while (monster.getNext()); @@ -414,7 +482,7 @@ var Attack = { if (monster) { do { - if (classid.indexOf(monster.classid) > -1 && getDistance(me, monster) <= range && (!spectype || (monster.spectype & spectype)) && this.checkMonster(monster)) { + if (classid.indexOf(monster.classid) > -1 && getDistance(center.x, center.y, monster.x, monster.y) <= range && (!spectype || (monster.spectype & spectype)) && this.checkMonster(monster)) { monsterList.push(copyUnit(monster)); } } while (monster.getNext()); @@ -478,30 +546,41 @@ var Attack = { result = ClassAttack.doAttack(target, attackCount % 15 === 0); - switch (result) { - case 1: - monsterList.shift(); + if (result) { + for (i = 0; i < gidAttack.length; i += 1) { + if (gidAttack[i].gid === target.gid) { + break; + } + } - break; - case 2: - case 3: - if (!(target.spectype & 0x7) && me.area !== 131) { - for (i = 0; i < gidAttack.length; i += 1) { - if (gidAttack[i].gid === target.gid) { - break; - } + if (i === gidAttack.length) { + gidAttack.push({gid: target.gid, attacks: 0}); + } + + gidAttack[i].attacks += 1; + + // Desync/bad position handler + switch (Config.AttackSkill[(target.spectype & 0x7) ? 1 : 3]) { + case 112: + // Tele in random direction with Blessed Hammer + if (gidAttack[i].attacks > 0 && gidAttack[i].attacks % ((target.spectype & 0x7) ? 5 : 15) === 0) { + Pather.moveTo(me.x + rand(-1, 1) * 4, me.y + rand(-1, 1) * 4); } - if (i === gidAttack.length) { - gidAttack.push({gid: target.gid, attacks: 0}); + break; + default: + // Flash with melee skills + if (gidAttack[i].attacks > 0 && gidAttack[i].attacks % ((target.spectype & 0x7) ? 5 : 15) === 0 && Skill.getRange(Config.AttackSkill[(target.spectype & 0x7) ? 1 : 3]) < 4) { + Packet.flash(me.gid); } - gidAttack[i].attacks += 1; + break; + } - if (gidAttack[i].attacks > 15) { - print("ÿc1Skipping " + target.name + " " + target.gid + " " + gidAttack[i].attacks); - monsterList.shift(); - } + // Skip non-unique monsters after 15 attacks, except in Throne of Destruction + if (me.area !== 131 && !(target.spectype & 0x7) && gidAttack[i].attacks > 15) { + print("ÿc1Skipping " + target.name + " " + target.gid + " " + gidAttack[i].attacks); + monsterList.shift(); } attackCount += 1; @@ -509,10 +588,8 @@ var Attack = { if (target.mode === 0 || target.mode === 12 || Config.FastPick === 2) { Pickit.fastPick(); } - - break; - default: - return false; + } else { + monsterList.shift(); } } else { monsterList.shift(); @@ -530,9 +607,9 @@ var Attack = { }, securePosition: function (x, y, range, timer, skipBlocked, special) { - if (arguments.length < 4) { + /*if (arguments.length < 4) { throw new Error("securePosition needs 4 arguments"); - } + }*/ var monster, monList, tick; @@ -701,7 +778,7 @@ var Attack = { result = Pather.getNearestWalkable(room[0], room[1], 18, 3); if (result) { - Pather.moveTo(result[0], result[1], 3); + Pather.moveTo(result[0], result[1], 3, spectype); //this.countUniques(); if (!this.clear(40, spectype)) { @@ -724,11 +801,11 @@ var Attack = { // Barb optimization if (me.classid === 4) { - if (!Attack.checkResist(unitA, ClassAttack.skillElement[(unitA.spectype & 0x7) ? 1 : 3])) { + if (!Attack.checkResist(unitA, Attack.getSkillElement(Config.AttackSkill[(unitA.spectype & 0x7) ? 1 : 3]))) { return 1; } - if (!Attack.checkResist(unitB, ClassAttack.skillElement[(unitB.spectype & 0x7) ? 1 : 3])) { + if (!Attack.checkResist(unitB, Attack.getSkillElement(Config.AttackSkill[(unitB.spectype & 0x7) ? 1 : 3]))) { return -1; } } @@ -800,30 +877,42 @@ var Attack = { }, // Open chests when clearing - openChests: function (range) { + openChests: function (range, x, y) { if (!Config.OpenChests) { return false; } + if (x === undefined || y === undefined) { + x = me.x; + y = me.y; + } + var i, unit, - ids = ["chest", "weaponrack", "armorstand"]; + list = [], + ids = ["chest", "chest3", "weaponrack", "armorstand"]; - for (i = 0; i < ids.length; i += 1) { - unit = getUnit(2, ids[i]); + unit = getUnit(2); - if (unit) { - do { - if ((getDistance(me, unit) <= range) && Misc.openChest(unit)) { - Pickit.pickItems(); - } - } while (unit.getNext()); + if (unit) { + do { + if (unit.name && getDistance(unit, x, y) <= range && ids.indexOf(unit.name.toLowerCase()) > -1) { + list.push(copyUnit(unit)); + } + } while (unit.getNext()); + } + + while (list.length) { + list.sort(Sort.units); + + if (Misc.openChest(list.shift())) { + Pickit.pickItems(); } } return true; }, - buildDodgeList: function () { + buildMonsterList: function () { var monster, monList = []; @@ -854,11 +943,11 @@ var Attack = { y: Math.round(Math.sin(Math.atan2(me.y - unit.y, me.x - unit.x)) * Config.DodgeRange + unit.y) }; - monList = this.buildDodgeList(); + monList = this.buildMonsterList(); monList.sort(Sort.units); - if (this.getMonsterCount(me.x, me.y, range, monList) === 0) { + if (this.getMonsterCount(me.x, me.y, 15, monList) === 0) { return true; } @@ -873,7 +962,8 @@ var Attack = { } function sortGrid(a, b) { - return getDistance(a.x, a.y, idealPos.x, idealPos.y) - getDistance(b.x, b.y, idealPos.x, idealPos.y); + //return getDistance(a.x, a.y, idealPos.x, idealPos.y) - getDistance(b.x, b.y, idealPos.x, idealPos.y); + return getDistance(b.x, b.y, unit.x, unit.y) - getDistance(a.x, a.y, unit.x, unit.y); } grid.sort(sortGrid); @@ -898,7 +988,7 @@ var Attack = { if (typeof index === "number") { //print("Dodge build time: " + (getTickCount() - tick)); - return Pather.moveTo(grid[index].x, grid[index].y, 3); + return Pather.moveTo(grid[index].x, grid[index].y, 0); } return false; @@ -906,6 +996,7 @@ var Attack = { getMonsterCount: function (x, y, range, list) { var i, + fire, count = 0, ignored = [243]; @@ -915,6 +1006,16 @@ var Attack = { } } + fire = getUnit(2, "fire"); + + if (fire) { + do { + if (getDistance(x, y, fire.x, fire.y) <= 4) { + count += 100; + } + } while (fire.getNext()); + } + return count; }, @@ -1079,6 +1180,8 @@ EnchantLoop: // Skip enchanted monsters } if (j === tempArray.length) { + //print("Skip Enchanted: " + unit.name); + return false; } } @@ -1212,24 +1315,32 @@ AuraLoop: // Skip monsters with auras }, // Check if a monster is immune to specified attack type - checkResist: function (unit, type, maxres) { - if (unit.type === 0) { // player + checkResist: function (unit, val, maxres) { + // Ignore player resistances + if (unit.type === 0) { return true; } - if (typeof maxres !== "number") { + var damageType = typeof val === "number" ? this.getSkillElement(val) : val; + + if (maxres === undefined) { maxres = 100; } - if (this.infinity && ["fire", "lightning", "cold"].indexOf(type) > -1) { + // Static handler + if (val === 42 && this.getResist(unit, damageType) < 100) { + return (unit.hp * 100 / 128) > Config.CastStatic; + } + + if (this.infinity && ["fire", "lightning", "cold"].indexOf(damageType) > -1) { if (!unit.getState(28)) { - return this.getResist(unit, type) < 117; + return this.getResist(unit, damageType) < 117; } - return this.getResist(unit, type) < maxres; + return this.getResist(unit, damageType) < maxres; } - return this.getResist(unit, type) < maxres; + return this.getResist(unit, damageType) < maxres; }, // Check if we have valid skills to attack a monster @@ -1282,18 +1393,22 @@ AuraLoop: // Skip monsters with auras return false; } - if (distance < 5 && (!unit.hasOwnProperty("mode") || (unit.mode !== 0 && unit.mode !== 12))) { + if (walk === true) { + walk = 1; + } + + if (distance < 4 && (!unit.hasOwnProperty("mode") || (unit.mode !== 0 && unit.mode !== 12))) { //me.overhead("Short range"); if (walk) { if (getDistance(me, unit) > 8 || checkCollision(me, unit, coll)) { Pather.walkTo(unit.x, unit.y, 3); } - - return true; + } else { + Pather.moveTo(unit.x, unit.y, 0); } - return Pather.moveTo(unit.x, unit.y, 0); + return !CollMap.checkColl(me, unit, coll); } var n, i, cx, cy, t, @@ -1326,13 +1441,26 @@ AuraLoop: // Skip monsters with auras for (i = 0; i < coords.length; i += 1) { // Valid position found - if (!CollMap.checkColl({x: coords[i].x, y: coords[i].y}, unit, coll, n > 0 ? 0 : 1)) { - //print("ÿc9optimal pos build time: ÿc2" + (getTickCount() - t)); // + " ÿc9distance from target: ÿc2" + getDistance(cx, cy, unit.x, unit.y)); + if (!CollMap.checkColl({x: coords[i].x, y: coords[i].y}, unit, coll, 1)) { + //print("ÿc9optimal pos build time: ÿc2" + (getTickCount() - t) + " ÿc9distance from target: ÿc2" + getDistance(cx, cy, unit.x, unit.y)); - if (walk) { + switch (walk) { + case 1: Pather.walkTo(coords[i].x, coords[i].y, 2); - } else { + + break; + case 2: + if (getDistance(me, coords[i]) < 6 && !CollMap.checkColl(me, coords[i], 0x5)) { + Pather.walkTo(coords[i].x, coords[i].y, 2); + } else { + Pather.moveTo(coords[i].x, coords[i].y, 1); + } + + break; + default: Pather.moveTo(coords[i].x, coords[i].y, 1); + + break; } return true; @@ -1342,7 +1470,7 @@ AuraLoop: // Skip monsters with auras } if (name) { - print("Couldn't get to " + name); + print("ÿc4Attackÿc0: No valid positions for: " + name); } return false; diff --git a/d2bs/kolbot/libs/common/Attacks/Amazon.js b/d2bs/kolbot/libs/common/Attacks/Amazon.js index 5f428b0a5..71b6ffca4 100644 --- a/d2bs/kolbot/libs/common/Attacks/Amazon.js +++ b/d2bs/kolbot/libs/common/Attacks/Amazon.js @@ -5,107 +5,91 @@ */ var ClassAttack = { - skillRange: [], - skillHand: [], - skillElement: [], bowCheck: false, lightFuryTick: 0, - init: function () { - var i; - - for (i = 0; i < Config.LowManaSkill.length; i += 1) { - Config.AttackSkill.push(Config.LowManaSkill[i]); - } - - for (i = 0; i < Config.AttackSkill.length; i += 1) { - this.skillHand[i] = getBaseStat("skills", Config.AttackSkill[i], "leftskill"); - this.skillElement[i] = Attack.getSkillElement(Config.AttackSkill[i]); - - switch (Config.AttackSkill[i]) { - case 0: // Normal Attack - this.skillRange[i] = Attack.usingBow() ? 20 : 3; - this.skillHand[i] = 2; // shift bypass - - break; - case 10: // Jab - case 14: // Power Strike - case 19: // Impale - case 30: // Fend - case 34: // Lightning Strike - this.skillRange[i] = 3; - - break; - case 24: // Charged Strike - this.skillRange[i] = 20; - - break; - default: // Every other skill - this.skillRange[i] = 20; - - break; - } - } - - this.bowCheck = Attack.usingBow(); - }, - doAttack: function (unit, preattack) { if (Config.MercWatch && Town.needMerc()) { Town.visitTown(); } - if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, this.skillElement[0]) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { - if (Math.round(getDistance(me, unit)) > this.skillRange[0] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[0], 0x4)) { - return 1; + if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, Config.AttackSkill[0]) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { + if (Math.round(getDistance(me, unit)) > Skill.getRange(Config.AttackSkill[0]) || checkCollision(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(Config.AttackSkill[0]), 0x4)) { + return false; } } - if (!Skill.cast(Config.AttackSkill[0], this.skillHand[0], unit)) { - return 2; - } + Skill.cast(Config.AttackSkill[0], Skill.getHand(Config.AttackSkill[0]), unit); - return 3; + return true; } - var index; + var index, checkSkill, + timedSkill = -1, + untimedSkill = -1; index = ((unit.spectype & 0x7) || unit.type === 0) ? 1 : 3; - if (Attack.checkResist(unit, this.skillElement[index])) { - switch (this.doCast(unit, index)) { - case 0: // total fail - return 1; - case false: // fail to cast - return 2; - } + // Get timed skill + if (Attack.getCustomAttack(unit)) { + checkSkill = Attack.getCustomAttack(unit)[0]; + } else { + checkSkill = Config.AttackSkill[index]; + } - return 3; + if (Attack.checkResist(unit, checkSkill)) { + timedSkill = checkSkill; + } else if (Config.AttackSkill[5] > -1 && Attack.checkResist(unit, Config.AttackSkill[5]) && ([56, 59].indexOf(Config.AttackSkill[5]) === -1 || Attack.validSpot(unit.x, unit.y))) { + timedSkill = Config.AttackSkill[5]; } - if (Config.AttackSkill[5] > -1 && Attack.checkResist(unit, this.skillElement[5])) { - switch (this.doCast(unit, 5)) { - case 0: // total fail - return 1; - case false: // fail to cast - return 2; - } + // Get untimed skill + if (Attack.getCustomAttack(unit)) { + checkSkill = Attack.getCustomAttack(unit)[1]; + } else { + checkSkill = Config.AttackSkill[index + 1]; + } - return 3; + if (Attack.checkResist(unit, checkSkill)) { + untimedSkill = checkSkill; + } else if (Config.AttackSkill[6] > -1 && Attack.checkResist(unit, Config.AttackSkill[6]) && ([56, 59].indexOf(Config.AttackSkill[6]) === -1 || Attack.validSpot(unit.x, unit.y))) { + untimedSkill = Config.AttackSkill[6]; } - if (Config.TeleStomp && me.getMerc() && Attack.checkResist(unit, "physical")) { - if (getDistance(me, unit) > 4) { - Pather.moveToUnit(unit); - } + // Low mana timed skill + if (Config.LowManaSkill[0] > -1 && Skill.getManaCost(timedSkill) > me.mp && Attack.checkResist(unit, Config.LowManaSkill[0])) { + timedSkill = Config.LowManaSkill[0]; + } + + // Low mana untimed skill + if (Config.LowManaSkill[1] > -1 && Skill.getManaCost(untimedSkill) > me.mp && Attack.checkResist(unit, Config.LowManaSkill[1])) { + untimedSkill = Config.LowManaSkill[1]; + } - delay(300); + switch (this.doCast(unit, timedSkill, untimedSkill)) { + case 0: // Fail + break; + case 1: // Success + return true; + case 2: // Try to telestomp + if (Config.TeleStomp && Attack.checkResist(unit, "physical") && !!me.getMerc()) { + while (Attack.checkMonster(unit)) { + if (getDistance(me, unit) > 3) { + Pather.moveToUnit(unit); + } + + this.doCast(unit, Config.AttackSkill[1], Config.AttackSkill[2]); + } - return 3; + return true; + } + + break; } - return 1; + // Couldn't attack + return false; }, afterAttack: function () { @@ -116,17 +100,21 @@ var ClassAttack = { needRepair = Town.needRepair(); - if (needRepair && needRepair.length) { // Repair check, mainly to restock arrows + if (needRepair && needRepair.length > 0) { // Repair check, mainly to restock arrows Town.visitTown(); } this.lightFuryTick = 0; }, - doCast: function (unit, index) { - var i, walk, - timed = index, - untimed = index + 1; + // Returns: 0 - fail, 1 - success, 2 - no valid attack skills + doCast: function (unit, timedSkill, untimedSkill) { + var i, walk; + + // No valid skills can be found + if (timedSkill < 0 && untimedSkill < 0) { + return 2; + } // Arrow/bolt check if (this.bowCheck) { @@ -146,70 +134,80 @@ var ClassAttack = { } } - // Low mana timed skill - if (Config.AttackSkill[timed] > -1 && Config.AttackSkill[Config.AttackSkill.length - 2] > -1 && Skill.getManaCost(Config.AttackSkill[timed]) > me.mp) { - timed = Config.AttackSkill.length - 2; - } + if (timedSkill > -1 && (!me.getState(121) || !Skill.isTimed(timedSkill))) { + switch (timedSkill) { + case 35: + if (!this.lightFuryTick || getTickCount() - this.lightFuryTick > Config.LightningFuryDelay * 1000) { + if (Math.round(getDistance(me, unit)) > Skill.getRange(timedSkill) || checkCollision(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(timedSkill), 0x4)) { + return 0; + } + } - if (Config.AttackSkill[timed] === 35) { - if (!this.lightFuryTick || getTickCount() - this.lightFuryTick > Config.LightningFuryDelay * 1000) { - if (Math.round(getDistance(me, unit)) > this.skillRange[timed] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[timed], 0x4)) { - return 0; + if (!unit.dead && Skill.cast(timedSkill, Skill.getHand(timedSkill), unit)) { + this.lightFuryTick = getTickCount(); } - } - if (Skill.cast(Config.AttackSkill[timed], this.skillHand[timed], unit)) { - this.lightFuryTick = getTickCount(); + return 1; + } - return true; + break; + default: + if (Skill.getRange(timedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { + return 0; } - return false; - } - } else if (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[timed])) { - if (Math.round(getDistance(me, unit)) > this.skillRange[timed] || checkCollision(me, unit, 0x4)) { - walk = (this.skillRange[timed] < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1)) || me.getState(139) || me.getState(140); + if (Math.round(getDistance(me, unit)) > Skill.getRange(timedSkill) || checkCollision(me, unit, 0x4)) { + // Allow short-distance walking for melee skills + walk = Skill.getRange(timedSkill) < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1); - // Walk short distances instead of tele for melee attacks - if (!Attack.getIntoPosition(unit, this.skillRange[timed], 0x4, walk)) { - return 0; + if (!Attack.getIntoPosition(unit, Skill.getRange(timedSkill), 0x4, walk)) { + return 0; + } } - } - return Skill.cast(Config.AttackSkill[timed], this.skillHand[timed], unit); - } + if (!unit.dead) { + Skill.cast(timedSkill, Skill.getHand(timedSkill), unit); + } - // Low mana untimed skill - if (Config.AttackSkill[untimed] > -1 && Config.AttackSkill[Config.AttackSkill.length - 1] > -1 && Skill.getManaCost(Config.AttackSkill[untimed]) > me.mp) { - untimed = Config.AttackSkill.length - 1; + return 1; + } } - if (Config.AttackSkill[untimed] > -1) { - if (Math.round(getDistance(me, unit)) > this.skillRange[untimed] || checkCollision(me, unit, 0x4)) { - walk = (this.skillRange[untimed] < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1)) || me.getState(139) || me.getState(140); + if (untimedSkill > -1) { + if (Skill.getRange(untimedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { + return 0; + } + + if (Math.round(getDistance(me, unit)) > Skill.getRange(untimedSkill) || checkCollision(me, unit, 0x4)) { + // Allow short-distance walking for melee skills + walk = Skill.getRange(untimedSkill) < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1); - // Walk short distances instead of tele for melee attacks - if (!Attack.getIntoPosition(unit, this.skillRange[untimed], 0x4, walk)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(untimedSkill), 0x4, walk)) { return 0; } } - return Skill.cast(Config.AttackSkill[untimed], this.skillHand[untimed], unit); + if (!unit.dead) { + Skill.cast(untimedSkill, Skill.getHand(untimedSkill), unit); + } + + return 1; } for (i = 0; i < 25; i += 1) { - delay(40); - if (!me.getState(121)) { break; } + + delay(40); } + // Wait for Lightning Fury timeout while (this.lightFuryTick && getTickCount() - this.lightFuryTick < Config.LightningFuryDelay * 1000) { delay(40); } - return false; + return 1; } }; \ No newline at end of file diff --git a/d2bs/kolbot/libs/common/Attacks/Assassin.js b/d2bs/kolbot/libs/common/Attacks/Assassin.js index d4bfb7698..ce2f76533 100644 --- a/d2bs/kolbot/libs/common/Attacks/Assassin.js +++ b/d2bs/kolbot/libs/common/Attacks/Assassin.js @@ -5,83 +5,29 @@ */ var ClassAttack = { - skillRange: [], - skillHand: [], - skillElement: [], lastTrapPos: {}, trapRange: 20, - init: function () { - var i; - - for (i = 0; i < Config.LowManaSkill.length; i += 1) { - Config.AttackSkill.push(Config.LowManaSkill[i]); - } - - for (i = 0; i < Config.AttackSkill.length; i += 1) { - this.skillHand[i] = getBaseStat("skills", Config.AttackSkill[i], "leftskill"); - this.skillElement[i] = Attack.getSkillElement(Config.AttackSkill[i]); - - switch (Config.AttackSkill[i]) { - case 0: // Normal Attack - this.skillRange[i] = Attack.usingBow() ? 20 : 3; - this.skillHand[i] = 2; // shift bypass - - break; - case 251: // Fire Blast - case 256: // Shock Web - case 257: // Blade Sentinel - case 266: // Blade Fury - this.skillRange[i] = 15; - - break; - case 255: // Dragon Talon - case 260: // Dragon Claw - case 270: // Dragon Tail - this.skillRange[i] = 3; - this.skillHand[i] = 2; // shift bypass - - break; - case 273: // Mind Blast - case 253: // Psychic Hammer - case 275: // Dragon Flight - this.skillRange[i] = 20; - - break; - // oskills - case 151: // Whirlwind - this.skillRange[i] = 10; - this.skillHand[i] = 0; - - break; - default: // Every other skill - this.skillRange[i] = 20; - - break; - } - } - }, - doAttack: function (unit, preattack) { if (Config.MercWatch && Town.needMerc()) { Town.visitTown(); } - if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, this.skillElement[0]) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { - if (Math.round(getDistance(me, unit)) > this.skillRange[0] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[0], 0x4)) { - return 1; + if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, Config.AttackSkill[0]) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { + if (Math.round(getDistance(me, unit)) > Skill.getRange(Config.AttackSkill[0]) || checkCollision(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(Config.AttackSkill[0]), 0x4)) { + return false; } } - if (!Skill.cast(Config.AttackSkill[0], this.skillHand[0], unit)) { - return 2; - } + Skill.cast(Config.AttackSkill[0], Skill.getHand(Config.AttackSkill[0]), unit); - return 3; + return true; } - var index, checkTraps; + var index, checkTraps, checkSkill, + timedSkill = -1, + untimedSkill = -1; index = ((unit.spectype & 0x7) || unit.type === 0) ? 1 : 3; checkTraps = this.checkTraps(unit); @@ -89,7 +35,7 @@ var ClassAttack = { if (checkTraps) { if (Math.round(getDistance(me, unit)) > this.trapRange || checkCollision(me, unit, 0x4)) { if (!Attack.getIntoPosition(unit, this.trapRange, 0x4) || (checkCollision(me, unit, 0x1) && (getCollision(unit.area, unit.x, unit.y) & 0x1))) { - return 1; + return false; } } @@ -101,29 +47,65 @@ var ClassAttack = { Skill.cast(264, 0); } - if (Attack.checkResist(unit, this.skillElement[index])) { - switch (this.doCast(unit, index)) { - case 0: // total fail - return 1; - case false: // fail to cast - return 2; - } + // Get timed skill + if (Attack.getCustomAttack(unit)) { + checkSkill = Attack.getCustomAttack(unit)[0]; + } else { + checkSkill = Config.AttackSkill[index]; + } - return 3; + if (Attack.checkResist(unit, checkSkill)) { + timedSkill = checkSkill; + } else if (Config.AttackSkill[5] > -1 && Attack.checkResist(unit, Config.AttackSkill[5]) && ([56, 59].indexOf(Config.AttackSkill[5]) === -1 || Attack.validSpot(unit.x, unit.y))) { + timedSkill = Config.AttackSkill[5]; } - if (Config.AttackSkill[5] > -1 && Attack.checkResist(unit, this.skillElement[5])) { - switch (this.doCast(unit, 5)) { - case 0: // total fail - return 1; - case false: // fail to cast - return 2; + // Get untimed skill + if (Attack.getCustomAttack(unit)) { + checkSkill = Attack.getCustomAttack(unit)[1]; + } else { + checkSkill = Config.AttackSkill[index + 1]; + } + + if (Attack.checkResist(unit, checkSkill)) { + untimedSkill = checkSkill; + } else if (Config.AttackSkill[6] > -1 && Attack.checkResist(unit, Config.AttackSkill[6]) && ([56, 59].indexOf(Config.AttackSkill[6]) === -1 || Attack.validSpot(unit.x, unit.y))) { + untimedSkill = Config.AttackSkill[6]; + } + + // Low mana timed skill + if (Config.LowManaSkill[0] > -1 && Skill.getManaCost(timedSkill) > me.mp && Attack.checkResist(unit, Config.LowManaSkill[0])) { + timedSkill = Config.LowManaSkill[0]; + } + + // Low mana untimed skill + if (Config.LowManaSkill[1] > -1 && Skill.getManaCost(untimedSkill) > me.mp && Attack.checkResist(unit, Config.LowManaSkill[1])) { + untimedSkill = Config.LowManaSkill[1]; + } + + switch (this.doCast(unit, timedSkill, untimedSkill)) { + case 0: // Fail + break; + case 1: // Success + return true; + case 2: // Try to telestomp + if (Config.TeleStomp && Attack.checkResist(unit, "physical") && !!me.getMerc()) { + while (Attack.checkMonster(unit)) { + if (getDistance(me, unit) > 3) { + Pather.moveToUnit(unit); + } + + this.doCast(unit, Config.AttackSkill[1], Config.AttackSkill[2]); + } + + return true; } - return 3; + break; } - return 1; + // Couldn't attack + return false; }, afterAttack: function () { @@ -131,64 +113,81 @@ var ClassAttack = { Precast.doPrecast(false); }, - doCast: function (unit, index) { - var i, walk, - timed = index, - untimed = index + 1; + // Returns: 0 - fail, 1 - success, 2 - no valid attack skills + doCast: function (unit, timedSkill, untimedSkill) { + var i, walk; - // Low mana timed skill - if (Config.AttackSkill[timed] > -1 && Config.AttackSkill[Config.AttackSkill.length - 2] > -1 && Skill.getManaCost(Config.AttackSkill[timed]) > me.mp) { - timed = Config.AttackSkill.length - 2; + // No valid skills can be found + if (timedSkill < 0 && untimedSkill < 0) { + return 2; } - if (Config.AttackSkill[timed] === 151) { - if (Math.round(getDistance(me, unit)) > this.skillRange[timed] || checkCollision(me, unit, 0x1)) { - if (!Attack.getIntoPosition(unit, this.skillRange[timed], 0x1)) { + if (timedSkill > -1 && (!me.getState(121) || !Skill.isTimed(timedSkill))) { + switch (timedSkill) { + case 151: // Whirlwind + if (Math.round(getDistance(me, unit)) > Skill.getRange(timedSkill) || checkCollision(me, unit, 0x1)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(timedSkill), 0x1)) { + return 0; + } + } + + if (!unit.dead) { + this.whirlwind(unit); + } + + return 1; + default: + if (Skill.getRange(timedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { return 0; } - } - return this.whirlwind(unit, timed); - } + if (Math.round(getDistance(me, unit)) > Skill.getRange(timedSkill) || checkCollision(me, unit, 0x4)) { + // Allow short-distance walking for melee skills + walk = Skill.getRange(timedSkill) < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1); - if (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[timed])) { - if (Math.round(getDistance(me, unit)) > this.skillRange[timed] || checkCollision(me, unit, 0x4)) { - walk = (this.skillRange[timed] < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1)) || me.getState(139) || me.getState(140); + if (!Attack.getIntoPosition(unit, Skill.getRange(timedSkill), 0x4, walk)) { + return 0; + } + } - if (!Attack.getIntoPosition(unit, this.skillRange[timed], 0x4, walk)) { - return 0; + if (!unit.dead) { + Skill.cast(timedSkill, Skill.getHand(timedSkill), unit); } - } - return unit.mode === 0 || unit.mode === 12 || Skill.cast(Config.AttackSkill[timed], this.skillHand[timed], unit); + return 1; + } } - // Low mana untimed skill - if (Config.AttackSkill[untimed] > -1 && Config.AttackSkill[Config.AttackSkill.length - 1] > -1 && Skill.getManaCost(Config.AttackSkill[untimed]) > me.mp) { - untimed = Config.AttackSkill.length - 1; - } + if (untimedSkill > -1) { + if (Skill.getRange(untimedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { + return 0; + } - if (Config.AttackSkill[untimed] > -1) { - if (Math.round(getDistance(me, unit)) > this.skillRange[untimed] || checkCollision(me, unit, 0x4)) { - walk = (this.skillRange[untimed] < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1)) || me.getState(139) || me.getState(140); + if (Math.round(getDistance(me, unit)) > Skill.getRange(untimedSkill) || checkCollision(me, unit, 0x4)) { + // Allow short-distance walking for melee skills + walk = Skill.getRange(untimedSkill) < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1); - if (!Attack.getIntoPosition(unit, this.skillRange[untimed], 0x4, walk)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(untimedSkill), 0x4, walk)) { return 0; } } - return unit.mode === 0 || unit.mode === 12 || Skill.cast(Config.AttackSkill[untimed], this.skillHand[untimed], unit); + if (!unit.dead) { + Skill.cast(untimedSkill, Skill.getHand(untimedSkill), unit); + } + + return 1; } for (i = 0; i < 25; i += 1) { - delay(40); - if (!me.getState(121)) { break; } + + delay(40); } - return false; + return 1; }, checkTraps: function (unit) { @@ -240,7 +239,7 @@ var ClassAttack = { return true; }, - whirlwind: function (unit, index) { + whirlwind: function (unit) { if (!Attack.checkMonster(unit)) { return true; } @@ -248,13 +247,18 @@ var ClassAttack = { var i, coords, angle, angles = [180, 175, -175, 170, -170, 165, -165, 150, -150, 135, -135, 45, -45, 90, -90]; + if (unit.spectype & 0x7) { + angles.unshift(120); + } + + me.runwalk = me.gametype; angle = Math.round(Math.atan2(me.y - unit.y, me.x - unit.x) * 180 / Math.PI); for (i = 0; i < angles.length; i += 1) { // get a better spot coords = [Math.round((Math.cos((angle + angles[i]) * Math.PI / 180)) * 4 + unit.x), Math.round((Math.sin((angle + angles[i]) * Math.PI / 180)) * 4 + unit.y)]; - if (!CollMap.checkColl(me, {x: coords[0], y: coords[1]}, 0x1, 0)) { - return Skill.cast(Config.AttackSkill[index], this.skillHand[index], coords[0], coords[1]); + if (!CollMap.checkColl(me, {x: coords[0], y: coords[1]}, 0x1, 1)) { + return Skill.cast(151, 0, coords[0], coords[1]); } } @@ -262,6 +266,6 @@ var ClassAttack = { return false; } - return Skill.cast(Config.AttackSkill[index], this.skillHand[index], me.x, me.y); + return Skill.cast(151, 0, me.x, me.y); } }; \ No newline at end of file diff --git a/d2bs/kolbot/libs/common/Attacks/Barbarian.js b/d2bs/kolbot/libs/common/Attacks/Barbarian.js index afde54b77..2c01d03a2 100644 --- a/d2bs/kolbot/libs/common/Attacks/Barbarian.js +++ b/d2bs/kolbot/libs/common/Attacks/Barbarian.js @@ -5,154 +5,116 @@ */ var ClassAttack = { - skillRange: [], - skillHand: [], - skillElement: [], - - init: function () { - var i; - - for (i = 0; i < Config.LowManaSkill.length; i += 1) { - Config.AttackSkill.push(Config.LowManaSkill[i]); - } - - for (i = 0; i < Config.AttackSkill.length; i += 1) { - this.skillHand[i] = getBaseStat("skills", Config.AttackSkill[i], "leftskill"); - this.skillElement[i] = Attack.getSkillElement(Config.AttackSkill[i]); - - switch (Config.AttackSkill[i]) { - case 0: // Normal Attack - this.skillRange[i] = Attack.usingBow() ? 20 : 3; - this.skillHand[i] = 2; // shift bypass - - break; - case 126: // Bash - case 133: // Double Swing - case 139: // Stun - case 144: // Concentrate - case 147: // Frenzy - case 152: // Berserk - case 232: // Feral Rage - this.skillRange[i] = 3; - this.skillHand[i] = 2; // shift bypass - - break; - case 130: // Howl - this.skillRange[i] = 10; - - break; - case 146: // Battle Cry - case 154: // War Cry - this.skillRange[i] = 4; - - break; - case 151: // Whirlwind - this.skillRange[i] = 10; - this.skillHand[i] = 0; - - break; - case 132: // Leap - this.skillRange[i] = 10; - - break; - default: // Every other skill - this.skillRange[i] = 20; - - break; - } - } - }, - doAttack: function (unit, preattack) { if (Config.MercWatch && Town.needMerc()) { Town.visitTown(); } - if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, this.skillElement[0]) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { - if (Math.round(getDistance(me, unit)) > this.skillRange[0] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[0], 0x4)) { - return 1; + if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, Attack.getSkillElement(Config.AttackSkill[0])) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { + if (Math.round(getDistance(me, unit)) > Skill.getRange(Config.AttackSkill[0]) || checkCollision(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(Config.AttackSkill[0]), 0x4)) { + return false; } } - if (!Skill.cast(Config.AttackSkill[0], this.skillHand[0], unit)) { - return 2; - } + Skill.cast(Config.AttackSkill[0], Skill.getHand(Config.AttackSkill[0]), unit); - return 3; + return true; } - var index; + var index, + attackSkill = -1; index = ((unit.spectype & 0x7) || unit.type === 0) ? 1 : 3; - return this.doCast(unit, index); + if (Attack.getCustomAttack(unit)) { + attackSkill = Attack.getCustomAttack(unit)[0]; + } else { + attackSkill = Config.AttackSkill[index]; + } + + if (!Attack.checkResist(unit, attackSkill)) { + attackSkill = -1; + + if (Config.AttackSkill[index + 1] > -1 && Attack.checkResist(unit, Config.AttackSkill[index + 1])) { + attackSkill = Config.AttackSkill[index + 1]; + } + } + + // Low mana skill + if (Skill.getManaCost(attackSkill) > me.mp && Config.LowManaSkill[0] > -1 && Attack.checkResist(unit, Config.LowManaSkill[0])) { + attackSkill = Config.LowManaSkill[0]; + } + + switch (this.doCast(unit, attackSkill)) { + case 0: // Fail + break; + case 1: // Success + return true; + case 2: // Telestomp with barbs is pointless + break; + } + + // Couldn't attack + return false; }, afterAttack: function (pickit) { + var needRepair; + + Misc.unShift(); Precast.doPrecast(false); + needRepair = Town.needRepair(); + + if (needRepair && needRepair.length > 0) { // Repair check + Town.visitTown(); + } + if (pickit) { this.findItem(me.area === 83 ? 60 : 20); } }, - doCast: function (unit, index) { + doCast: function (unit, attackSkill) { var walk; - if (unit.mode === 0 || unit.mode === 12) { - return 3; + if (attackSkill < 0) { + return 2; } - // Low mana skill - if (Config.AttackSkill[index] > -1 && Config.AttackSkill[Config.AttackSkill.length - 1] > -1 && Skill.getManaCost(Config.AttackSkill[index]) > me.mp) { - index = Config.AttackSkill.length - 1; - } + switch (attackSkill) { + case 151: + if (Math.ceil(getDistance(me, unit)) > Skill.getRange(attackSkill) || checkCollision(me, unit, 0x1)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(attackSkill), 0x1, 2)) { + return 0; + } + } - // Check Immunities - if (!Attack.checkResist(unit, this.skillElement[index])) { - // already on last skill - if (index === Config.AttackSkill.length - 1) { - return 1; + if (!unit.dead) { + this.whirlwind(unit); } - if (Config.AttackSkill[index + 1] > -1 && Attack.checkResist(unit, this.skillElement[index + 1])) { - index = index + 1; - } else { - return 1; + return 1; + default: + if (Skill.getRange(attackSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { + return 0; } - } - if (Config.AttackSkill[index] === 151) { - if (Math.round(getDistance(me, unit)) > this.skillRange[index] || checkCollision(me, unit, 0x1)) { - //Pather.moveToUnit(unit, 0, 0, false, true); + if (Math.round(getDistance(me, unit)) > Skill.getRange(attackSkill) || checkCollision(me, unit, 0x4)) { + walk = Skill.getRange(attackSkill) < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1); - if (!Attack.getIntoPosition(unit, this.skillRange[index], 0x1)) { - return 1; + if (!Attack.getIntoPosition(unit, Skill.getRange(attackSkill), 0x4, walk)) { + return 0; } } - if (!this.whirlwind(unit)) { - if (Config.AttackSkill[index + 1] > 0) { - index = index + 1; - } else { - return 2; - } - } else { - return 3; + if (!unit.dead) { + Skill.cast(attackSkill, Skill.getHand(attackSkill), unit); } - } - - if (Math.round(getDistance(me, unit)) > this.skillRange[index] || checkCollision(me, unit, 0x4)) { - walk = (this.skillRange[index] < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1)); - // walk short distances instead of tele for melee attacks - if (!Attack.getIntoPosition(unit, this.skillRange[index], 0x4, walk)) { - return 1; - } + return 1; } - - return Skill.cast(Config.AttackSkill[index], this.skillHand[index], unit) ? 3 : 2; }, whirlwind: function (unit) { @@ -167,14 +129,14 @@ var ClassAttack = { angles.unshift(120); } - me.runwalk = me.gametype; + //me.runwalk = 0; angle = Math.round(Math.atan2(me.y - unit.y, me.x - unit.x) * 180 / Math.PI); for (i = 0; i < angles.length; i += 1) { // get a better spot coords = [Math.round((Math.cos((angle + angles[i]) * Math.PI / 180)) * 4 + unit.x), Math.round((Math.sin((angle + angles[i]) * Math.PI / 180)) * 4 + unit.y)]; - if (!CollMap.checkColl(me, {x: coords[0], y: coords[1]}, 0x1, 0)) { - return Skill.cast(151, 0, coords[0], coords[1]); + if (!CollMap.checkColl(me, {x: coords[0], y: coords[1]}, 0x1, 1)) { + return Skill.cast(151, Skill.getHand(151), coords[0], coords[1]); } } @@ -182,7 +144,7 @@ var ClassAttack = { return false; } - return Skill.cast(151, 0, me.x, me.y); + return Skill.cast(151, Skill.getHand(151), me.x, me.y); }, checkCloseMonsters: function (range) { @@ -193,8 +155,8 @@ var ClassAttack = { if (monster) { do { if (getDistance(me, monster) <= range && Attack.checkMonster(monster) && !checkCollision(me, monster, 0x4) && - (Attack.checkResist(monster, this.skillElement[(monster.spectype & 0x7) ? 1 : 3]) || - (Config.AttackSkill[3] > -1 && Attack.checkResist(monster, this.skillElement[3])))) { + (Attack.checkResist(monster, Attack.getSkillElement(Config.AttackSkill[(monster.spectype & 0x7) ? 1 : 3])) || + (Config.AttackSkill[3] > -1 && Attack.checkResist(monster, Attack.getSkillElement(Config.AttackSkill[3]))))) { return true; } } while (monster.getNext()); @@ -244,7 +206,7 @@ MainLoop: corpse = corpseList.shift(); if (this.checkCorpse(corpse)) { - if (getDistance(me, corpse) > 9 || checkCollision(me, corpse, 0x1)) { + if (getDistance(me, corpse) > 30 || checkCollision(me, corpse, 0x1)) { Pather.moveToUnit(corpse); } @@ -254,7 +216,7 @@ MainLoop: CorpseLoop: for (j = 0; j < 3; j += 1) { - Skill.cast(142, 0, corpse); + Skill.cast(142, 3, corpse); tick = getTickCount(); @@ -311,4 +273,4 @@ CorpseLoop: return false; } -}; +}; \ No newline at end of file diff --git a/d2bs/kolbot/libs/common/Attacks/Druid.js b/d2bs/kolbot/libs/common/Attacks/Druid.js index b3e1495ac..3fc46460f 100644 --- a/d2bs/kolbot/libs/common/Attacks/Druid.js +++ b/d2bs/kolbot/libs/common/Attacks/Druid.js @@ -5,51 +5,6 @@ */ var ClassAttack = { - skillRange: [], - skillHand: [], - skillElement: [], - - init: function () { - var i; - - for (i = 0; i < Config.LowManaSkill.length; i += 1) { - Config.AttackSkill.push(Config.LowManaSkill[i]); - } - - for (i = 0; i < Config.AttackSkill.length; i += 1) { - this.skillHand[i] = getBaseStat("skills", Config.AttackSkill[i], "leftskill"); - this.skillElement[i] = Attack.getSkillElement(Config.AttackSkill[i]); - - switch (Config.AttackSkill[i]) { - case 0: // Normal Attack - this.skillRange[i] = Attack.usingBow() ? 20 : 3; - this.skillHand[i] = 2; // shift bypass - - break; - case 225: // Firestorm - case 229: // Molten Boulder - case 230: // Arctic Blast - this.skillRange[i] = 10; - - break; - case 234: // Fissure - case 244: // Volcano - this.skillRange[i] = 15; - - break; - case 240: // Twister - case 245: // Tornado - this.skillRange[i] = 5; - - break; - default: // Every other skill - this.skillRange[i] = 20; - - break; - } - } - }, - doAttack: function (unit, preattack) { if (Config.MercWatch && Town.needMerc()) { Town.visitTown(); @@ -63,57 +18,83 @@ var ClassAttack = { Skill.cast(235, 0); } - if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, this.skillElement[0]) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { - if (Math.floor(getDistance(me, unit)) > this.skillRange[0] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[0], 0x4)) { - return 1; + if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, Config.AttackSkill[0]) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { + if (Math.round(getDistance(me, unit)) > Skill.getRange(Config.AttackSkill[0]) || checkCollision(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(Config.AttackSkill[0]), 0x4)) { + return false; } } - if (!Skill.cast(Config.AttackSkill[0], this.skillHand[0], unit)) { - return 2; - } + Skill.cast(Config.AttackSkill[0], Skill.getHand(Config.AttackSkill[0]), unit); - return 3; + return true; } - var index; + var index, checkSkill, + timedSkill = -1, + untimedSkill = -1; index = ((unit.spectype & 0x7) || unit.type === 0) ? 1 : 3; - if (Attack.checkResist(unit, this.skillElement[index])) { - switch (this.doCast(unit, index)) { - case 0: // total fail - return 1; - case false: // fail to cast - return 2; - } + // Get timed skill + if (Attack.getCustomAttack(unit)) { + checkSkill = Attack.getCustomAttack(unit)[0]; + } else { + checkSkill = Config.AttackSkill[index]; + } - return 3; + if (Attack.checkResist(unit, checkSkill)) { + timedSkill = checkSkill; + } else if (Config.AttackSkill[5] > -1 && Attack.checkResist(unit, Config.AttackSkill[5]) && ([56, 59].indexOf(Config.AttackSkill[5]) === -1 || Attack.validSpot(unit.x, unit.y))) { + timedSkill = Config.AttackSkill[5]; } - if (Config.AttackSkill[5] > -1 && Attack.checkResist(unit, this.skillElement[5])) { - switch (this.doCast(unit, 5)) { - case 0: // total fail - return 1; - case false: // fail to cast - return 2; - } + // Get untimed skill + if (Attack.getCustomAttack(unit)) { + checkSkill = Attack.getCustomAttack(unit)[1]; + } else { + checkSkill = Config.AttackSkill[index + 1]; + } - return 3; + if (Attack.checkResist(unit, checkSkill)) { + untimedSkill = checkSkill; + } else if (Config.AttackSkill[6] > -1 && Attack.checkResist(unit, Config.AttackSkill[6]) && ([56, 59].indexOf(Config.AttackSkill[6]) === -1 || Attack.validSpot(unit.x, unit.y))) { + untimedSkill = Config.AttackSkill[6]; } - if ((me.getState(144) && Attack.checkResist(unit, "cold")) || (Config.TeleStomp && me.getMerc() && Attack.checkResist(unit, "physical"))) { - if (getDistance(me, unit) > 4) { - Pather.moveToUnit(unit); - } + // Low mana timed skill + if (Config.LowManaSkill[0] > -1 && Skill.getManaCost(timedSkill) > me.mp && Attack.checkResist(unit, Config.LowManaSkill[0])) { + timedSkill = Config.LowManaSkill[0]; + } - delay(300); + // Low mana untimed skill + if (Config.LowManaSkill[1] > -1 && Skill.getManaCost(untimedSkill) > me.mp && Attack.checkResist(unit, Config.LowManaSkill[1])) { + untimedSkill = Config.LowManaSkill[1]; + } - return 3; + switch (this.doCast(unit, timedSkill, untimedSkill)) { + case 0: // Fail + break; + case 1: // Success + return true; + case 2: // Try to telestomp + if (Config.TeleStomp && Attack.checkResist(unit, "physical") && !!me.getMerc()) { + while (Attack.checkMonster(unit)) { + if (getDistance(me, unit) > 3) { + Pather.moveToUnit(unit); + } + + this.doCast(unit, Config.AttackSkill[1], Config.AttackSkill[2]); + } + + return true; + } + + break; } - return 1; + // Couldn't attack + return false; }, afterAttack: function () { @@ -121,57 +102,81 @@ var ClassAttack = { Precast.doPrecast(false); }, - doCast: function (unit, index) { - var i, walk, - timed = index, - untimed = index + 1; + // Returns: 0 - fail, 1 - success, 2 - no valid attack skills + doCast: function (unit, timedSkill, untimedSkill) { + var i, walk; - // Low mana timed skill - if (Config.AttackSkill[timed] > -1 && Config.AttackSkill[Config.AttackSkill.length - 2] > -1 && Skill.getManaCost(Config.AttackSkill[timed]) > me.mp) { - timed = Config.AttackSkill.length - 2; + // No valid skills can be found + if (timedSkill < 0 && untimedSkill < 0) { + return 2; } - if (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[timed])) { - if (Math.floor(getDistance(me, unit)) > this.skillRange[timed] || checkCollision(me, unit, 0x4)) { - walk = (this.skillRange[untimed] < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1)) || me.getState(139) || me.getState(140); + if (timedSkill > -1 && (!me.getState(121) || !Skill.isTimed(timedSkill))) { + switch (timedSkill) { + case 245: // Tornado + if (Math.round(getDistance(me, unit)) > Skill.getRange(timedSkill) || checkCollision(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(timedSkill), 0x4)) { + return 0; + } + } + + // Randomized x coord changes tornado path and prevents constant missing + if (!unit.dead) { + Skill.cast(timedSkill, Skill.getHand(timedSkill), unit.x + rand(-2, 2), unit.y); + } - if (!Attack.getIntoPosition(unit, this.skillRange[timed], 0x4, walk)) { + return 1; + default: + if (Skill.getRange(timedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { return 0; } - } - if (Config.AttackSkill[timed] === 245) { - return Skill.cast(Config.AttackSkill[timed], this.skillHand[timed], unit.x + rand(-2, 2), unit.y); - } + if (Math.round(getDistance(me, unit)) > Skill.getRange(timedSkill) || checkCollision(me, unit, 0x4)) { + // Allow short-distance walking for melee skills + walk = Skill.getRange(timedSkill) < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1); - return Skill.cast(Config.AttackSkill[timed], this.skillHand[timed], unit); - } + if (!Attack.getIntoPosition(unit, Skill.getRange(timedSkill), 0x4, walk)) { + return 0; + } + } - // Low mana untimed skill - if (Config.AttackSkill[untimed] > -1 && Config.AttackSkill[Config.AttackSkill.length - 1] > -1 && Skill.getManaCost(Config.AttackSkill[untimed]) > me.mp) { - untimed = Config.AttackSkill.length - 1; + if (!unit.dead) { + Skill.cast(timedSkill, Skill.getHand(timedSkill), unit); + } + + return 1; + } } - if (Config.AttackSkill[untimed] > -1) { - if (Math.floor(getDistance(me, unit)) > this.skillRange[untimed] || checkCollision(me, unit, 0x4)) { - walk = (this.skillRange[untimed] < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1)) || me.getState(139) || me.getState(140); + if (untimedSkill > -1) { + if (Skill.getRange(untimedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { + return 0; + } + + if (Math.round(getDistance(me, unit)) > Skill.getRange(untimedSkill) || checkCollision(me, unit, 0x4)) { + // Allow short-distance walking for melee skills + walk = Skill.getRange(untimedSkill) < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1); - if (!Attack.getIntoPosition(unit, this.skillRange[untimed], 0x4, walk)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(untimedSkill), 0x4, walk)) { return 0; } } - return Skill.cast(Config.AttackSkill[untimed], this.skillHand[untimed], unit); + if (!unit.dead) { + Skill.cast(untimedSkill, Skill.getHand(untimedSkill), unit); + } + + return 1; } for (i = 0; i < 25; i += 1) { - delay(40); - if (!me.getState(121)) { break; } + + delay(40); } - return false; + return 1; } }; \ No newline at end of file diff --git a/d2bs/kolbot/libs/common/Attacks/Necromancer.js b/d2bs/kolbot/libs/common/Attacks/Necromancer.js index ec5608357..2a5159d8c 100644 --- a/d2bs/kolbot/libs/common/Attacks/Necromancer.js +++ b/d2bs/kolbot/libs/common/Attacks/Necromancer.js @@ -5,54 +5,13 @@ */ var ClassAttack = { - skillRange: [], - skillHand: [], - skillElement: [], - curseState: [], novaTick: 0, + cursesSet: false, + curseState: [], - init: function () { + initCurses: function () { var i; - for (i = 0; i < Config.LowManaSkill.length; i += 1) { - Config.AttackSkill.push(Config.LowManaSkill[i]); - } - - for (i = 0; i < Config.AttackSkill.length; i += 1) { - this.skillHand[i] = getBaseStat("skills", Config.AttackSkill[i], "leftskill"); - this.skillElement[i] = Attack.getSkillElement(Config.AttackSkill[i]); - - switch (Config.AttackSkill[i]) { - case 0: // Normal Attack - this.skillRange[i] = Attack.usingBow() ? 20 : 3; - this.skillHand[i] = 2; // shift bypass - - break; - case 73: // Poison Dagger - this.skillRange[i] = 3; - - break; - case 92: // Poison Nova - this.skillRange[i] = 8; - - break; - case 67: // Teeth - case 84: // Bone Spear - case 93: // Bone Spirit - this.skillRange[i] = 15; - - break; - case 500: // Summoner - this.skillRange[i] = 5; - - break; - default: // Every other skill - this.skillRange[i] = 20; - - break; - } - } - for (i = 0; i < Config.Curse.length; i += 1) { switch (Config.Curse[i]) { case 0: //nothing @@ -106,109 +65,132 @@ var ClassAttack = { break; } } + + this.cursesSet = true; }, doAttack: function (unit, preattack) { + if (!this.cursesSet) { + this.initCurses(); + } + if (Config.MercWatch && Town.needMerc()) { Town.visitTown(); } - if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, this.skillElement[0]) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { - if (Math.round(getDistance(me, unit)) > this.skillRange[0] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[0], 0x4)) { - return 1; + if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, Config.AttackSkill[0]) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { + if (Math.round(getDistance(me, unit)) > Skill.getRange(Config.AttackSkill[0]) || checkCollision(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(Config.AttackSkill[0]), 0x4)) { + return false; } } - if (!Skill.cast(Config.AttackSkill[0], this.skillHand[0], unit)) { - return 2; - } + Skill.cast(Config.AttackSkill[0], Skill.getHand(Config.AttackSkill[0]), unit); - return 3; + return true; } - var index; + var index, checkSkill, + timedSkill = -1, + untimedSkill = -1; index = ((unit.spectype & 0x7) || unit.type === 0) ? 1 : 3; if (Config.Curse[0] > 0 && this.isCursable(unit) && (unit.spectype & 0x7) && !unit.getState(this.curseState[0])) { if (getDistance(me, unit) > 25 || checkCollision(me, unit, 0x4)) { if (!Attack.getIntoPosition(unit, 25, 0x4)) { - return 1; + return false; } } - if (!Skill.cast(Config.Curse[0], 0, unit)) { - return 2; - } + Skill.cast(Config.Curse[0], 0, unit); - return 3; + return true; } if (Config.Curse[1] > 0 && this.isCursable(unit) && !(unit.spectype & 0x7) && !unit.getState(this.curseState[1])) { if (getDistance(me, unit) > 25 || checkCollision(me, unit, 0x4)) { if (!Attack.getIntoPosition(unit, 25, 0x4)) { - return 1; + return false; } } - if (!Skill.cast(Config.Curse[1], 0, unit)) { - return 2; - } + Skill.cast(Config.Curse[1], 0, unit); - return 3; + return true; } - if (Attack.checkResist(unit, this.skillElement[index])) { - switch (this.doCast(unit, index)) { - case 0: // total fail - return 1; - case false: // fail to cast - return 2; - } + // Get timed skill + if (Attack.getCustomAttack(unit)) { + checkSkill = Attack.getCustomAttack(unit)[0]; + } else { + checkSkill = Config.AttackSkill[index]; + } - if (Config.ActiveSummon) { - this.raiseArmy(); - } + if (Attack.checkResist(unit, checkSkill)) { + timedSkill = checkSkill; + } else if (Config.AttackSkill[5] > -1 && Attack.checkResist(unit, Config.AttackSkill[5]) && ([56, 59].indexOf(Config.AttackSkill[5]) === -1 || Attack.validSpot(unit.x, unit.y))) { + timedSkill = Config.AttackSkill[5]; + } - this.explodeCorpses(unit); + // Get untimed skill + if (Attack.getCustomAttack(unit)) { + checkSkill = Attack.getCustomAttack(unit)[1]; + } else { + checkSkill = Config.AttackSkill[index + 1]; + } - return 3; + if (Attack.checkResist(unit, checkSkill)) { + untimedSkill = checkSkill; + } else if (Config.AttackSkill[6] > -1 && Attack.checkResist(unit, Config.AttackSkill[6]) && ([56, 59].indexOf(Config.AttackSkill[6]) === -1 || Attack.validSpot(unit.x, unit.y))) { + untimedSkill = Config.AttackSkill[6]; } - if (Config.AttackSkill[5] > -1 && Attack.checkResist(unit, this.skillElement[5])) { - switch (this.doCast(unit, 5)) { - case 0: // total fail - return 1; - case false: // fail to cast - return 2; - } + // Low mana timed skill + if (Config.LowManaSkill[0] > -1 && Skill.getManaCost(timedSkill) > me.mp && Attack.checkResist(unit, Config.LowManaSkill[0])) { + timedSkill = Config.LowManaSkill[0]; + } + + // Low mana untimed skill + if (Config.LowManaSkill[1] > -1 && Skill.getManaCost(untimedSkill) > me.mp && Attack.checkResist(unit, Config.LowManaSkill[1])) { + untimedSkill = Config.LowManaSkill[1]; + } + switch (this.doCast(unit, timedSkill, untimedSkill)) { + case 0: // Fail + break; + case 1: // Success if (Config.ActiveSummon) { this.raiseArmy(); } this.explodeCorpses(unit); - return 3; - } + return true; + case 2: // Try to telestomp + if (Config.TeleStomp && Attack.checkResist(unit, "physical") && !!me.getMerc()) { + while (Attack.checkMonster(unit)) { + if (getDistance(me, unit) > 3) { + Pather.moveToUnit(unit); + } - if (Attack.checkResist(unit, "physical") && me.getMerc()) { - if (Config.TeleStomp && getDistance(me, unit) > 3) { - Pather.moveToUnit(unit); - } + this.doCast(unit, Config.AttackSkill[1], Config.AttackSkill[2]); - if (Config.ActiveSummon) { - this.raiseArmy(); - } + if (Config.ActiveSummon) { + this.raiseArmy(); + } - this.explodeCorpses(unit); - delay(300); + this.explodeCorpses(unit); + } + + return true; + } - return 3; + break; } - return 1; + // Couldn't attack + return false; }, afterAttack: function () { @@ -218,80 +200,109 @@ var ClassAttack = { this.novaTick = 0; }, - doCast: function (unit, index) { - var i, - timed = index, - untimed = index + 1; + // Returns: 0 - fail, 1 - success, 2 - no valid attack skills + doCast: function (unit, timedSkill, untimedSkill) { + var i, walk; - // Low mana timed skill - if (Config.AttackSkill[timed] > -1 && Config.AttackSkill[Config.AttackSkill.length - 2] > -1 && Skill.getManaCost(Config.AttackSkill[timed]) > me.mp) { - timed = Config.AttackSkill.length - 2; + // No valid skills can be found + if (timedSkill < 0 && untimedSkill < 0) { + return 2; } - if (Config.AttackSkill[timed] === 92) { - if (!this.novaTick || getTickCount() - this.novaTick > Config.PoisonNovaDelay * 1000) { - if (Math.round(getDistance(me, unit)) > this.skillRange[timed] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[timed], 0x4)) { + // Check for bodies to exploit for CorpseExplosion before committing to an attack for non-summoner type necros + if (Config.Skeletons + Config.SkeletonMages + Config.Revives === 0) { + if (this.checkCorpseNearMonster(unit)) { + this.explodeCorpses(unit); + } + } + + if (timedSkill > -1 && (!me.getState(121) || !Skill.isTimed(timedSkill))) { + switch (timedSkill) { + case 92: // Poison Nova + if (!this.novaTick || getTickCount() - this.novaTick > Config.PoisonNovaDelay * 1000) { + if (Math.round(getDistance(me, unit)) > Skill.getRange(timedSkill) || checkCollision(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(timedSkill), 0x4)) { + return 0; + } + } + + if (!unit.dead && Skill.cast(timedSkill, Skill.getHand(timedSkill), unit)) { + this.novaTick = getTickCount(); + } + } + + break; + case 500: // Pure Summoner + if (Math.round(getDistance(me, unit)) > Skill.getRange(timedSkill) || checkCollision(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(timedSkill), 0x4)) { return 0; } } - if (Skill.cast(Config.AttackSkill[timed], this.skillHand[timed], unit)) { - this.novaTick = getTickCount(); + delay(300); - return true; + break; + default: + if (Skill.getRange(timedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { + return 0; } - return false; - } - } else if (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[timed])) { - if (Math.round(getDistance(me, unit)) > this.skillRange[timed] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[timed], 0x4)) { - return 0; + if (Math.round(getDistance(me, unit)) > Skill.getRange(timedSkill) || checkCollision(me, unit, 0x4)) { + // Allow short-distance walking for melee skills + walk = Skill.getRange(timedSkill) < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1); + + if (!Attack.getIntoPosition(unit, Skill.getRange(timedSkill), 0x4, walk)) { + return 0; + } } - } - if (Config.AttackSkill[timed] === 500) { - delay(300); + if (!unit.dead) { + Skill.cast(timedSkill, Skill.getHand(timedSkill), unit); + } - return true; + break; } - - return Skill.cast(Config.AttackSkill[timed], this.skillHand[timed], unit); } - // Low mana untimed skill - if (Config.AttackSkill[untimed] > -1 && Config.AttackSkill[Config.AttackSkill.length - 1] > -1 && Skill.getManaCost(Config.AttackSkill[untimed]) > me.mp) { - untimed = Config.AttackSkill.length - 1; - } + if (untimedSkill > -1) { + if (Skill.getRange(untimedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { + return 0; + } - if (Config.AttackSkill[untimed] > -1) { - if (Math.round(getDistance(me, unit)) > this.skillRange[untimed] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[untimed], 0x4)) { + if (Math.round(getDistance(me, unit)) > Skill.getRange(untimedSkill) || checkCollision(me, unit, 0x4)) { + // Allow short-distance walking for melee skills + walk = Skill.getRange(untimedSkill) < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1); + + if (!Attack.getIntoPosition(unit, Skill.getRange(untimedSkill), 0x4, walk)) { return 0; } } - return Skill.cast(Config.AttackSkill[untimed], this.skillHand[untimed], unit); + if (!unit.dead) { + Skill.cast(untimedSkill, Skill.getHand(untimedSkill), unit); + } + + return 1; } for (i = 0; i < 25; i += 1) { - delay(40); - if (!me.getState(121)) { break; } + + delay(40); } + // Delay for Poison Nova while (this.novaTick && getTickCount() - this.novaTick < Config.PoisonNovaDelay * 1000) { delay(40); } - return false; + return 1; }, isCursable: function (unit) { - if (typeof copyUnit(unit).name === "undefined" || unit.name.indexOf(getLocaleString(11086)) > -1) { // "Possessed" + if (copyUnit(unit).name === undefined || unit.name.indexOf(getLocaleString(11086)) > -1) { // "Possessed" return false; } @@ -418,7 +429,8 @@ MainLoop: return false; } - var corpseList = [], + var i, + corpseList = [], range = Math.floor((me.getSkill(Config.ExplodeCorpses, 1) + 7) / 3), corpse = getUnit(1, -1, 12); @@ -426,25 +438,68 @@ MainLoop: do { if (getDistance(unit, corpse) <= range && this.checkCorpse(corpse)) { corpseList.push(copyUnit(corpse)); + } + } while (corpse.getNext()); - if (corpseList.length >= 2) { // Explode 2 corpses per cycle, so we can leave some for summoning + //Shuffle the corpseList so if running multiple necrobots they explode separate corpses not the same ones + if (corpseList.length > 1) { + corpseList = corpseList.shuffle(); + } + + if (Config.Skeletons + Config.SkeletonMages + Config.Revives === 0) { + // We don't need corpses as we are not a Summoner Necro, Spam CE till monster dies or we run out of bodies. + do { + corpse = corpseList.shift(); + + if (corpse) { + if (!unit.dead && this.checkCorpse(corpse) && getDistance(corpse, unit) <= range) { + me.overhead("Exploding: " + corpse.classid + " " + corpse.name + " id:" + corpse.gid); // Added corpse ID so I can see when it blows another monster with the same ClassID and Name + + if (Skill.cast(Config.ExplodeCorpses, 0, corpse)) { + delay(me.ping + 1); + } + } + } + } while (corpseList.length > 0); + } else { + // We are a Summoner Necro, we should conserve corpses, only blow 2 at a time so we can check for needed re-summons. + for (i = 0; i <= 1; i += 1) { + if (corpseList.length > 0) { + corpse = corpseList.shift(); + + if (corpse) { + me.overhead("Exploding: " + corpse.classid + " " + corpse.name); + + if (Skill.cast(Config.ExplodeCorpses, 0, corpse)) { + delay(200); + } + } + } else { break; } } - } while (corpse.getNext()); + } } - while (corpseList.length > 0) { - corpse = corpseList.shift(); + return true; + }, - me.overhead("Exploding: " + corpse.classid + " " + corpse.name); + checkCorpseNearMonster: function (monster, range) { + var corpse = getUnit(1, -1, 12); - if (Skill.cast(Config.ExplodeCorpses, 0, corpse)) { - delay(200); - } + if (range === undefined) { // Assume CorpseExplosion if no range specified + range = Math.floor((me.getSkill(Config.ExplodeCorpses, 1) + 7) / 3); } - return true; + if (corpse) { + do { + if (getDistance(corpse, monster) <= range) { + return true; + } + } while (corpse.getNext()); + } + + return false; }, checkCorpse: function (unit, revive) { @@ -452,7 +507,7 @@ MainLoop: return false; } - if (typeof revive === "undefined") { + if (revive === undefined) { revive = false; } diff --git a/d2bs/kolbot/libs/common/Attacks/Paladin.js b/d2bs/kolbot/libs/common/Attacks/Paladin.js index 8e3abca55..497bc6c2e 100644 --- a/d2bs/kolbot/libs/common/Attacks/Paladin.js +++ b/d2bs/kolbot/libs/common/Attacks/Paladin.js @@ -5,113 +5,80 @@ */ var ClassAttack = { - skillRange: [], - skillHand: [], - skillElement: [], - - init: function () { - var i; - - for (i = 0; i < Config.LowManaSkill.length; i += 1) { - Config.AttackSkill.push(Config.LowManaSkill[i]); - } - - for (i = 0; i < Config.AttackSkill.length; i += 1) { - this.skillHand[i] = getBaseStat("skills", Config.AttackSkill[i], "leftskill"); - this.skillElement[i] = Attack.getSkillElement(Config.AttackSkill[i]); - - switch (Config.AttackSkill[i]) { - case 0: // Normal Attack - this.skillRange[i] = Attack.usingBow() ? 20 : 3; - this.skillHand[i] = 2; // shift bypass - - break; - case 96: // Sacrifice - case 97: // Smite - case 106: // Zeal - case 116: // Conversion - this.skillRange[i] = 4; - this.skillHand[i] = 2; // shift bypass - - break; - case 112: // Blessed Hammer - this.skillRange[i] = 3; - - break; - case 101: // Holy Bolt - this.skillRange[i] = 5; - - break; - case 107: // Charge - this.skillRange[i] = 10; - - break; - case 121: // Fist of the Heavens - this.skillRange[i] = 20; - - break; - default: // Every other skill - this.skillRange[i] = 25; - - break; - } - } - }, - doAttack: function (unit, preattack) { if (Config.MercWatch && Town.needMerc()) { + print("mercwatch"); Town.visitTown(); } - if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, this.skillElement[0]) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { - if (getDistance(me, unit) > this.skillRange[0] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[0], 0x4)) { - return 1; + if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, Config.AttackSkill[0]) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { + if (getDistance(me, unit) > Skill.getRange(Config.AttackSkill[0]) || checkCollision(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(Config.AttackSkill[0]), 0x4)) { + return false; } } - if (!Skill.cast(Config.AttackSkill[0], this.skillHand[0], unit)) { - return 2; - } + Skill.cast(Config.AttackSkill[0], Skill.getHand(Config.AttackSkill[0]), unit); - return 3; + return true; } - var index; + var index, + attackSkill = -1, + aura = -1; index = ((unit.spectype & 0x7) || unit.type === 0) ? 1 : 3; - if (Attack.checkResist(unit, this.skillElement[index])) { - if (this.skillRange[index] < 4 && checkCollision(me, unit, 0x1) && !Attack.validSpot(unit.x, unit.y)) { - return 1; - } + if (Attack.getCustomAttack(unit)) { + attackSkill = Attack.getCustomAttack(unit)[0]; + aura = Attack.getCustomAttack(unit)[1]; + } else { + attackSkill = Config.AttackSkill[index]; + aura = Config.AttackSkill[index + 1]; + } - switch (this.doCast(unit, index)) { - case 0: // total fail - return 1; - case false: // fail to cast - return 2; + // Monster immune to primary skill + if (!Attack.checkResist(unit, attackSkill)) { + // Reset skills + attackSkill = -1; + aura = -1; + + // Set to secondary if not immune + if (Config.AttackSkill[5] > -1 && Attack.checkResist(unit, Config.AttackSkill[5])) { + attackSkill = Config.AttackSkill[5]; + aura = Config.AttackSkill[6]; } + } - return 3; + // Low mana skill + if (Config.LowManaSkill[0] > -1 && Skill.getManaCost(attackSkill) > me.mp && Attack.checkResist(unit, Config.LowManaSkill[0])) { + attackSkill = Config.LowManaSkill[0]; + aura = Config.LowManaSkill[1]; } - if (Config.AttackSkill[5] > -1 && Attack.checkResist(unit, this.skillElement[5])) { - if (this.skillRange[5] < 4 && checkCollision(me, unit, 0x1) && (getCollision(unit.area, unit.x, unit.y) & 0x1)) { - return 1; - } + switch (this.doCast(unit, attackSkill, aura)) { + case 0: // Fail + break; + case 1: // Success + return true; + case 2: // Try to telestomp + if (Config.TeleStomp && Attack.checkResist(unit, "physical") && !!me.getMerc()) { + while (Attack.checkMonster(unit)) { + if (getDistance(me, unit) > 3) { + Pather.moveToUnit(unit); + } + + this.doCast(unit, Config.AttackSkill[1], Config.AttackSkill[2]); + } - switch (this.doCast(unit, 5)) { - case 0: // total fail - return 1; - case false: // fail to cast - return 2; + return true; } - return 3; + break; } - return 1; + // Couldn't attack + return false; }, afterAttack: function () { @@ -123,85 +90,135 @@ var ClassAttack = { } }, - doCast: function (unit, index) { - var i, walk, - atkSkill = index, - aura = index + 1; - - // Low mana skill - if (Config.AttackSkill[atkSkill] > -1 && Config.AttackSkill[Config.AttackSkill.length - 2] > -1 && Skill.getManaCost(Config.AttackSkill[atkSkill]) > me.mp) { - atkSkill = Config.AttackSkill.length - 2; - } + doCast: function (unit, attackSkill, aura) { + var i, walk; - // Low mana aura - if (Config.AttackSkill[aura] > -1 && Config.AttackSkill[Config.AttackSkill.length - 1] > -1 && Skill.getManaCost(Config.AttackSkill[aura]) > me.mp) { - aura = Config.AttackSkill.length - 1; + if (attackSkill < 0) { + return false; } - if (Config.AttackSkill[atkSkill] === 112) { + switch (attackSkill) { + case 112: if (unit.classid === 691 && Config.AvoidDolls) { this.dollAvoid(unit); - if (Config.AttackSkill[aura] > -1) { - Skill.setSkill(Config.AttackSkill[aura], 0); + if (aura > -1) { + Skill.setSkill(aura, 0); } - return Skill.cast(Config.AttackSkill[atkSkill], this.skillHand[atkSkill], unit); + Skill.cast(attackSkill, Skill.getHand(attackSkill), unit); + + return 1; } if (!this.getHammerPosition(unit)) { - print("can't get to " + unit.name); + //print("Can't get to " + unit.name); + + // Fallback to secondary skill if it exists + if (Config.AttackSkill[5] > -1 && Config.AttackSkill[5] !== 112 && Attack.checkResist(unit, Config.AttackSkill[5])) { + return this.doCast(unit, Config.AttackSkill[5], Config.AttackSkill[6]); + } - return (unit.spectype & 0x7) ? 2 : 0; // continue attacking a boss monster + return 0; } - if (getDistance(me, unit) > 7) { // increase pvp aggressiveness - return false; + if (getDistance(me, unit) > 9 || unit.dead) { + //print(getDistance(me, unit)); + + return 1; } - if (Config.AttackSkill[aura] > -1) { - Skill.setSkill(Config.AttackSkill[aura], 0); + if (aura > -1) { + Skill.setSkill(aura, 0); } for (i = 0; i < 3; i += 1) { - Skill.cast(Config.AttackSkill[atkSkill], this.skillHand[atkSkill], unit); + Skill.cast(attackSkill, Skill.getHand(attackSkill), unit); - if (!Attack.checkMonster(unit) || getDistance(me, unit) > 5 || unit.type === 0) { + if (!Attack.checkMonster(unit) || getDistance(me, unit) > 9 || unit.type === 0) { break; } } - return true; - } - - if (Config.AttackSkill[atkSkill] === 101) { - if (getDistance(me, unit) > this.skillRange[atkSkill] + 3 || CollMap.checkColl(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[atkSkill], 0x4)) { + return 1; + case 101: + if (getDistance(me, unit) > Skill.getRange(attackSkill) + 3 || CollMap.checkColl(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(attackSkill), 0x4)) { return 0; } } CollMap.reset(); - if (getDistance(me, unit) > this.skillRange[atkSkill] || CollMap.checkColl(me, unit, 0x2004, 2)) { - if (!Attack.getIntoPosition(unit, this.skillRange[atkSkill], 0x2004, true)) { + if (getDistance(me, unit) > Skill.getRange(attackSkill) || CollMap.checkColl(me, unit, 0x2004, 2)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(attackSkill), 0x2004, true)) { return 0; } } - } else if (Math.floor(getDistance(me, unit)) > this.skillRange[atkSkill] || checkCollision(me, unit, 0x4)) { - walk = (Config.AttackSkill[atkSkill] !== 97 && (this.skillRange[atkSkill] < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1))) || me.getState(139) || me.getState(140); - // walk short distances instead of tele for melee attacks. teleport if failed to walk - if (!Attack.getIntoPosition(unit, this.skillRange[atkSkill], 0x4, walk)) { + if (!unit.dead) { + if (aura > -1) { + Skill.setSkill(aura, 0); + } + + Skill.cast(attackSkill, Skill.getHand(attackSkill), unit); + } + + return 1; + case 121: // FoH + if (!me.getState(121)) { + if (getDistance(me, unit) > Skill.getRange(attackSkill) || CollMap.checkColl(me, unit, 0x2004, 2)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(attackSkill), 0x2004, true)) { + return 0; + } + } + + if (!unit.dead) { + if (aura > -1) { + Skill.setSkill(aura, 0); + } + + Skill.cast(attackSkill, Skill.getHand(attackSkill), unit); + + return 1; + } + } + + break; + default: + if (Skill.getRange(attackSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { return 0; } + + if (Math.floor(getDistance(me, unit)) > Skill.getRange(attackSkill) || checkCollision(me, unit, 0x4)) { + walk = attackSkill !== 97 && Skill.getRange(attackSkill) < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1); + + // walk short distances instead of tele for melee attacks. teleport if failed to walk + if (!Attack.getIntoPosition(unit, Skill.getRange(attackSkill), 0x4, walk)) { + return 0; + } + } + + if (!unit.dead) { + if (aura > -1) { + Skill.setSkill(aura, 0); + } + + Skill.cast(attackSkill, Skill.getHand(attackSkill), unit); + } + + return 1; } - if (Config.AttackSkill[aura] > -1) { - Skill.setSkill(Config.AttackSkill[aura], 0); + for (i = 0; i < 25; i += 1) { + if (!me.getState(121)) { + break; + } + + delay(40); } - return unit.mode === 0 || unit.mode === 12 || Skill.cast(Config.AttackSkill[atkSkill], this.skillHand[atkSkill], unit); + return 1; }, dollAvoid: function (unit) { @@ -218,7 +235,7 @@ var ClassAttack = { }, getHammerPosition: function (unit) { - var i, x, y, positions, + var i, x, y, positions, check, baseId = getBaseStat("monstats", unit.classid, "baseid"), size = getBaseStat("monstats2", baseId, "sizex"); @@ -237,10 +254,10 @@ var ClassAttack = { case 1: // Monster x = (unit.mode === 2 || unit.mode === 15) && getDistance(me, unit) < 10 && getDistance(me, unit.targetx, unit.targety) > 5 ? unit.targetx : unit.x; y = (unit.mode === 2 || unit.mode === 15) && getDistance(me, unit) < 10 && getDistance(me, unit.targetx, unit.targety) > 5 ? unit.targety : unit.y; - positions = [[x + 2, y], [x, y + 3], [x - 2, y - 1]]; + positions = [[x + 2, y + 1], [x, y + 3], [x + 2, y - 1], [x - 2, y + 2], [x - 5, y]]; if (size === 3) { - positions.unshift([x + size - 1, y + size - 1]); + positions.unshift([x + 2, y + 2]); } break; @@ -253,10 +270,13 @@ var ClassAttack = { } for (i = 0; i < positions.length; i += 1) { - if (Attack.validSpot(positions[i][0], positions[i][1])) { - this.reposition(positions[i][0], positions[i][1]); + check = { + x: positions[i][0], + y: positions[i][1] + }; - if (!checkCollision(me, unit, 0x1)) { + if (Attack.validSpot(check.x, check.y) && !CollMap.checkColl(unit, check, 0x4, 0)) { + if (this.reposition(positions[i][0], positions[i][1])) { return true; } } @@ -266,31 +286,21 @@ var ClassAttack = { }, reposition: function (x, y) { - while (!me.idle) { - delay(40); - } + var i; - if (getDistance(me, x, y) > 0) { + if (Math.round(getDistance(me, x, y) > 0)) { if (Pather.teleport && !me.inTown && me.getStat(97, 54)) { if (getDistance(me, x, y) > 40) { Pather.moveTo(x, y); } else { - //Pather.teleportTo(x, y); - Skill.cast(54, 0, x, y); + Pather.teleportTo(x, y, 3); } } else { - if (Config.Vigor) { - Skill.setSkill(115, 0); - } - - me.move(x, y); + Misc.click(0, 0, x, y); + delay(200); } } - while (!me.idle) { - delay(40); - } - return true; } }; \ No newline at end of file diff --git a/d2bs/kolbot/libs/common/Attacks/Sorceress.js b/d2bs/kolbot/libs/common/Attacks/Sorceress.js index b4c09d1e0..a1d7d8754 100644 --- a/d2bs/kolbot/libs/common/Attacks/Sorceress.js +++ b/d2bs/kolbot/libs/common/Attacks/Sorceress.js @@ -5,72 +5,9 @@ */ var ClassAttack = { - skillRange: [], - skillHand: [], - skillElement: [], - - init: function () { - var i; - - for (i = 0; i < Config.LowManaSkill.length; i += 1) { - Config.AttackSkill.push(Config.LowManaSkill[i]); - } - - for (i = 0; i < Config.AttackSkill.length; i += 1) { - this.skillHand[i] = getBaseStat("skills", Config.AttackSkill[i], "leftskill"); - this.skillElement[i] = Attack.getSkillElement(Config.AttackSkill[i]); - - switch (Config.AttackSkill[i]) { - case 0: // Normal Attack - this.skillRange[i] = Attack.usingBow() ? 20 : 3; - this.skillHand[i] = 2; // shift bypass - - break; - case 38: // Charged Bolt - this.skillRange[i] = 6; - - break; - case 42: // Static Field - if (me.gametype) { - this.skillRange[i] = Math.floor((me.getSkill(42, 1) + 4) * 2 / 3); - } else { - this.skillRange[i] = 25; - } - - break; - case 44: // Frost Nova - this.skillRange[i] = 5; - - break; - case 48: // Nova - this.skillRange[i] = 7; - - break; - case 49: // Lightning - case 53: // Chain Lightning - this.skillRange[i] = 15; - - break; - case 64: // Frozen Orb - this.skillRange[i] = 15; - - break; - // oskills - case 106: // Zeal - this.skillRange[i] = 3; - this.skillHand[i] = 2; // shift bypass - - break; - default: // Every other skill - this.skillRange[i] = 25; - - break; - } - } - }, - doAttack: function (unit, preattack) { if (Config.MercWatch && Town.needMerc()) { + print("mercwatch"); Town.visitTown(); } @@ -78,35 +15,58 @@ var ClassAttack = { Skill.cast(58, 0); } - if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, this.skillElement[0]) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { - if (Math.round(getDistance(me, unit)) > this.skillRange[0] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[0], 0x4)) { - return 1; + if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, Config.AttackSkill[0]) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { + if (Math.round(getDistance(me, unit)) > Skill.getRange(Config.AttackSkill[0]) || checkCollision(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(Config.AttackSkill[0]), 0x4)) { + return false; } } - if (!Skill.cast(Config.AttackSkill[0], this.skillHand[0], unit)) { - return 2; - } + Skill.cast(Config.AttackSkill[0], Skill.getHand(Config.AttackSkill[0]), unit); - return 3; + return true; } - var index, staticRange, timedIndex, untimedIndex; + var index, staticRange, checkSkill, + timedSkill = -1, + untimedSkill = -1; // Static - if (Config.CastStatic < 100 && me.getSkill(42, 1) && Attack.checkResist(unit, "lightning") && Config.StaticList.indexOf(unit.name) > -1 && Math.round(unit.hp * 100 / unit.hpmax) > Config.CastStatic) { + if (Config.CastStatic < 100 && me.getSkill(42, 1) && Attack.checkResist(unit, "lightning") && Config.StaticList.some( + function (id) { + if (unit) { + switch (typeof id) { + case "number": + if (unit.classid && unit.classid === id) { + return true; + } + + break; + case "string": + if (unit.name && unit.name.toLowerCase() === id.toLowerCase()) { + return true; + } + + break; + default: + throw new Error("Bad Config.StaticList settings."); + } + } + + return false; + } + ) && Math.round(unit.hp * 100 / unit.hpmax) > Config.CastStatic) { staticRange = Math.floor((me.getSkill(42, 1) + 4) * 2 / 3); - while (Math.round(unit.hp * 100 / unit.hpmax) > Config.CastStatic && Attack.checkMonster(unit)) { + while (!me.dead && Math.round(unit.hp * 100 / unit.hpmax) > Config.CastStatic && Attack.checkMonster(unit)) { if (getDistance(me, unit) > staticRange || checkCollision(me, unit, 0x4)) { if (!Attack.getIntoPosition(unit, staticRange, 0x4)) { - return 1; + return false; } } if (!Skill.cast(42, 0)) { - return 2; + break; } } } @@ -114,98 +74,129 @@ var ClassAttack = { index = ((unit.spectype & 0x7) || unit.type === 0) ? 1 : 3; // Get timed skill - if (Attack.checkResist(unit, this.skillElement[index]) && ([56, 59].indexOf(Config.AttackSkill[index]) === -1 || Attack.validSpot(unit.x, unit.y))) { // added a check for blizz/meteor because they can't be cast on invalid spot - timedIndex = index; - } else if (Config.AttackSkill[5] > -1 && Attack.checkResist(unit, this.skillElement[5]) && ([56, 59].indexOf(Config.AttackSkill[5]) === -1 || Attack.validSpot(unit.x, unit.y))) { - timedIndex = 5; + if (Attack.getCustomAttack(unit)) { + checkSkill = Attack.getCustomAttack(unit)[0]; + } else { + checkSkill = Config.AttackSkill[index]; + } + + if (Attack.checkResist(unit, checkSkill) && ([56, 59].indexOf(checkSkill) === -1 || Attack.validSpot(unit.x, unit.y))) { + timedSkill = checkSkill; + } else if (Config.AttackSkill[5] > -1 && Attack.checkResist(unit, Config.AttackSkill[5]) && ([56, 59].indexOf(Config.AttackSkill[5]) === -1 || Attack.validSpot(unit.x, unit.y))) { + timedSkill = Config.AttackSkill[5]; } // Get untimed skill - if (Config.AttackSkill[index + 1] > -1 && Attack.checkResist(unit, this.skillElement[index + 1]) && (Config.AttackSkill[index + 1] !== 42 || Math.round(unit.hp * 100 / unit.hpmax) > Config.CastStatic)) { - untimedIndex = index + 1; - } else if (Config.AttackSkill[6] > -1 && Attack.checkResist(unit, this.skillElement[6]) && (Config.AttackSkill[6] !== 42 || Math.round(unit.hp * 100 / unit.hpmax) > Config.CastStatic)) { - untimedIndex = 6; + if (Attack.getCustomAttack(unit)) { + checkSkill = Attack.getCustomAttack(unit)[1]; + } else { + checkSkill = Config.AttackSkill[index + 1]; + } + + if (Attack.checkResist(unit, checkSkill) && ([56, 59].indexOf(checkSkill) === -1 || Attack.validSpot(unit.x, unit.y))) { + untimedSkill = checkSkill; + } else if (Config.AttackSkill[6] > -1 && Attack.checkResist(unit, Config.AttackSkill[6]) && ([56, 59].indexOf(Config.AttackSkill[6]) === -1 || Attack.validSpot(unit.x, unit.y))) { + untimedSkill = Config.AttackSkill[6]; } - if (!timedIndex && !untimedIndex) { - // Check if we can merc stomp the boss - if (Config.TeleStomp && index === 1 && !!me.getMerc() && Attack.checkResist(unit, "physical")) { - // Spam attacks - timedIndex = 1; - untimedIndex = Config.AttackSkill[2] > -1 ? 2 : false; + // Low mana timed skill + if (Config.LowManaSkill[0] > -1 && Skill.getManaCost(timedSkill) > me.mp && Attack.checkResist(unit, Config.LowManaSkill[0])) { + timedSkill = Config.LowManaSkill[0]; + } + + // Low mana untimed skill + if (Config.LowManaSkill[1] > -1 && Skill.getManaCost(untimedSkill) > me.mp && Attack.checkResist(unit, Config.LowManaSkill[1])) { + untimedSkill = Config.LowManaSkill[1]; + } - // dirty override until a good solution presents itself + switch (this.doCast(unit, timedSkill, untimedSkill)) { + case 0: // Fail + break; + case 1: // Success + return true; + case 2: // Try to telestomp + if (Config.TeleStomp && Attack.checkResist(unit, "physical") && !!me.getMerc() && Attack.validSpot(unit.x, unit.y)) { while (Attack.checkMonster(unit)) { - if (getDistance(me, unit) > 5) { + if (getDistance(me, unit) > 3) { Pather.moveToUnit(unit); } - this.doCast(unit, timedIndex, untimedIndex); + this.doCast(unit, Config.AttackSkill[1], Config.AttackSkill[2]); } - } else { - return 1; + + return true; } - } - switch (this.doCast(unit, timedIndex, untimedIndex)) { - case 0: // total fail - return 1; - case false: // fail to cast - return 2; + break; } - return 3; + // Couldn't attack + return false; }, afterAttack: function () { Precast.doPrecast(false); }, - doCast: function (unit, timed, untimed) { - var i; + // Returns: 0 - fail, 1 - success, 2 - no valid attack skills + doCast: function (unit, timedSkill, untimedSkill) { + var i, walk; - // Low mana timed skill - if (timed && Config.AttackSkill[timed] > -1 && Config.AttackSkill[Config.AttackSkill.length - 2] > -1 && Skill.getManaCost(Config.AttackSkill[timed]) > me.mp) { - timed = Config.AttackSkill.length - 2; + // No valid skills can be found + if (timedSkill < 0 && untimedSkill < 0) { + return 2; } - if (timed && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[timed]))) { - if (Math.round(getDistance(me, unit)) > this.skillRange[timed] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[timed], 0x4)) { + if (timedSkill > -1 && (!me.getState(121) || !Skill.isTimed(timedSkill))) { + if (Skill.getRange(timedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { + return 0; + } + + if (Math.round(getDistance(me, unit)) > Skill.getRange(timedSkill) || checkCollision(me, unit, 0x4)) { + // Allow short-distance walking for melee skills + walk = Skill.getRange(timedSkill) < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1); + + if (!Attack.getIntoPosition(unit, Skill.getRange(timedSkill), 0x4, walk)) { return 0; } } - if (Config.AttackSkill[timed] === 59) { - return Skill.cast(Config.AttackSkill[timed], this.skillHand[timed], unit.x + rand(-2, 2), unit.y + rand(-2, 2)); + if (!unit.dead && !checkCollision(me, unit, 0x4)) { + Skill.cast(timedSkill, Skill.getHand(timedSkill), unit); } - return Skill.cast(Config.AttackSkill[timed], this.skillHand[timed], unit); + return 1; } - // Low mana untimed skill - if (untimed && Config.AttackSkill[untimed] > -1 && Config.AttackSkill[Config.AttackSkill.length - 1] > -1 && Skill.getManaCost(Config.AttackSkill[untimed]) > me.mp) { - untimed = Config.AttackSkill.length - 1; - } + if (untimedSkill > -1) { + if (Skill.getRange(untimedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { + return 0; + } + + if (Math.round(getDistance(me, unit)) > Skill.getRange(untimedSkill) || checkCollision(me, unit, 0x4)) { + // Allow short-distance walking for melee skills + walk = Skill.getRange(untimedSkill) < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1); - if (untimed && Config.AttackSkill[untimed] > -1) { - if (Math.round(getDistance(me, unit)) > this.skillRange[untimed] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[untimed], 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(untimedSkill), 0x4, walk)) { return 0; } } - return Skill.cast(Config.AttackSkill[untimed], this.skillHand[untimed], unit); + if (!unit.dead) { + Skill.cast(untimedSkill, Skill.getHand(untimedSkill), unit); + } + + return 1; } for (i = 0; i < 25; i += 1) { - delay(40); - if (!me.getState(121)) { break; } + + delay(40); } - return false; + return 1; } }; \ No newline at end of file diff --git a/d2bs/kolbot/libs/common/Attacks/Wereform.js b/d2bs/kolbot/libs/common/Attacks/Wereform.js index 409caf2e0..33fa313a0 100644 --- a/d2bs/kolbot/libs/common/Attacks/Wereform.js +++ b/d2bs/kolbot/libs/common/Attacks/Wereform.js @@ -5,75 +5,88 @@ */ var ClassAttack = { - skillRange: [], - skillHand: [], - skillElement: [], + doAttack: function (unit, preattack) { + if (Config.MercWatch && Town.needMerc()) { + Town.visitTown(); + } - init: function () { - var i; + if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, Config.AttackSkill[0]) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { + if (Math.round(getDistance(me, unit)) > Skill.getRange(Config.AttackSkill[0]) || checkCollision(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(Config.AttackSkill[0]), 0x4)) { + return false; + } + } - for (i = 0; i < Config.LowManaSkill.length; i += 1) { - Config.AttackSkill.push(Config.LowManaSkill[i]); + Skill.cast(Config.AttackSkill[0], Skill.getHand(Config.AttackSkill[0]), unit); + + return true; } - for (i = 0; i < Config.AttackSkill.length; i += 1) { - this.skillHand[i] = getBaseStat("skills", Config.AttackSkill[i], "leftskill"); - this.skillElement[i] = Attack.getSkillElement(Config.AttackSkill[i]); + var index, checkSkill, + timedSkill = -1, + untimedSkill = -1; - switch (Config.AttackSkill[i]) { - case 0: // Normal Attack - this.skillRange[i] = Attack.usingBow() ? 20 : 3; - this.skillHand[i] = 2; // shift bypass + index = ((unit.spectype & 0x7) || unit.type === 0) ? 1 : 3; - break; - case 232: // Feral Rage - case 233: // Maul - case 238: // Rabies - case 239: // Fire Claws - case 242: // Hunger - case 248: // Fury - this.skillRange[i] = 3; - this.skillHand[i] = 2; + // Get timed skill + if (Attack.getCustomAttack(unit)) { + checkSkill = Attack.getCustomAttack(unit)[0]; + } else { + checkSkill = Config.AttackSkill[index]; + } - break; - case 243: // Shock Wave - this.skillRange[i] = 8; + if (Attack.checkResist(unit, checkSkill)) { + timedSkill = checkSkill; + } else if (Config.AttackSkill[5] > -1 && Attack.checkResist(unit, Config.AttackSkill[5]) && ([56, 59].indexOf(Config.AttackSkill[5]) === -1 || Attack.validSpot(unit.x, unit.y))) { + timedSkill = Config.AttackSkill[5]; + } - break; - default: // Every other skill - this.skillRange[i] = 20; + // Get untimed skill + if (Attack.getCustomAttack(unit)) { + checkSkill = Attack.getCustomAttack(unit)[1]; + } else { + checkSkill = Config.AttackSkill[index + 1]; + } - break; - } + if (Attack.checkResist(unit, checkSkill)) { + untimedSkill = checkSkill; + } else if (Config.AttackSkill[6] > -1 && Attack.checkResist(unit, Config.AttackSkill[6]) && ([56, 59].indexOf(Config.AttackSkill[6]) === -1 || Attack.validSpot(unit.x, unit.y))) { + untimedSkill = Config.AttackSkill[6]; } - this.bowCheck = Attack.usingBow(); - }, + // Low mana timed skill + if (Config.LowManaSkill[0] > -1 && Skill.getManaCost(timedSkill) > me.mp && Attack.checkResist(unit, Config.LowManaSkill[0])) { + timedSkill = Config.LowManaSkill[0]; + } - doAttack: function (unit, preattack) { - if (Config.MercWatch && Town.needMerc()) { - Town.visitTown(); + // Low mana untimed skill + if (Config.LowManaSkill[1] > -1 && Skill.getManaCost(untimedSkill) > me.mp && Attack.checkResist(unit, Config.LowManaSkill[1])) { + untimedSkill = Config.LowManaSkill[1]; } - if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, this.skillElement[0]) && (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[0]))) { - if (Math.round(getDistance(me, unit)) > this.skillRange[0] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[0], 0x4)) { - return 1; + switch (this.doCast(unit, timedSkill, untimedSkill)) { + case 0: // Fail + break; + case 1: // Success + return true; + case 2: // Try to telestomp + if (Config.TeleStomp && Attack.checkResist(unit, "physical") && !!me.getMerc()) { + while (Attack.checkMonster(unit)) { + if (getDistance(me, unit) > 3) { + Pather.moveToUnit(unit); + } + + this.doCast(unit, Config.AttackSkill[1], Config.AttackSkill[2]); } - } - if (!Skill.cast(Config.AttackSkill[0], this.skillHand[0], unit)) { - return 2; + return true; } - return 3; + break; } - var index; - - index = ((unit.spectype & 0x7) || unit.type === 0) ? 1 : 3; - - return this.doCast(unit, index); + // Couldn't attack + return false; }, afterAttack: function () { @@ -81,43 +94,81 @@ var ClassAttack = { Precast.doPrecast(false); }, - doCast: function (unit, index) { - // Low mana skill - if (Config.AttackSkill[index] > -1 && Config.AttackSkill[Config.AttackSkill.length - 1] > -1 && Skill.getManaCost(Config.AttackSkill[index]) > me.mp) { - index = Config.AttackSkill.length - 1; + // Returns: 0 - fail, 1 - success, 2 - no valid attack skills + doCast: function (unit, timedSkill, untimedSkill) { + var i; + + // No valid skills can be found + if (timedSkill < 0 && untimedSkill < 0) { + return 2; } - // Check Immunities - if (!Attack.checkResist(unit, this.skillElement[index])) { - if (Config.AttackSkill[index + 1] > -1 && Attack.checkResist(unit, this.skillElement[index + 1])) { - index = index + 1; - } else { - return 1; + if (timedSkill > -1 && (!me.getState(121) || !Skill.isTimed(timedSkill))) { + if (Skill.getRange(timedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { + return 0; + } + + // Teleport closer + if (Math.ceil(getDistance(me, unit)) > 10) { + Misc.unShift(); + + if (!Attack.getIntoPosition(unit, 10, 0x4)) { + return 0; + } + } + + Misc.shapeShift(Config.Wereform); + + if (Math.round(getDistance(me, unit)) > Skill.getRange(timedSkill) || checkCollision(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(timedSkill), 0x4, true)) { + return 0; + } + } + + if (!unit.dead) { + Skill.cast(timedSkill, Skill.getHand(timedSkill), unit); } - } - if (this.skillRange[index] < 4 && !Attack.validSpot(unit.x, unit.y)) { return 1; } - // Teleport closer - if (Math.round(getDistance(me, unit)) > 10) { - Misc.unShift(); + if (untimedSkill > -1) { + if (Skill.getRange(untimedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { + return 0; + } + + // Teleport closer + if (Math.ceil(getDistance(me, unit)) > 10) { + Misc.unShift(); - if (!Attack.getIntoPosition(unit, 5, 0x4)) { - return 1; + if (!Attack.getIntoPosition(unit, 10, 0x4)) { + return 0; + } } - } - Misc.shapeShift(Config.Wereform); + Misc.shapeShift(Config.Wereform); - // Walk closer - if (Math.round(getDistance(me, unit)) > this.skillRange[index] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[index], 0x4, true)) { - return 1; + if (Math.round(getDistance(me, unit)) > Skill.getRange(untimedSkill) || checkCollision(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(untimedSkill), 0x4, true)) { + return 0; + } } + + if (!unit.dead) { + Skill.cast(untimedSkill, Skill.getHand(untimedSkill), unit); + } + + return 1; + } + + for (i = 0; i < 25; i += 1) { + if (!me.getState(121)) { + break; + } + + delay(40); } - return Skill.cast(Config.AttackSkill[index], this.skillHand[index], unit) ? 3 : 2; + return 1; } }; \ No newline at end of file diff --git a/d2bs/kolbot/libs/common/CollMap.js b/d2bs/kolbot/libs/common/CollMap.js index 4d96c9d07..ee2364b78 100644 --- a/d2bs/kolbot/libs/common/CollMap.js +++ b/d2bs/kolbot/libs/common/CollMap.js @@ -95,7 +95,7 @@ var CollMap = new function () { }; this.coordsInRoom = function (x, y, room) { - if (x >= room.x * 5 && x < room.x * 5 + room.xsize && y >= room.y * 5 && y < room.y * 5 + room.ysize) { + if (room && x >= room.x * 5 && x < room.x * 5 + room.xsize && y >= room.y * 5 && y < room.y * 5 + room.ysize) { return true; } diff --git a/d2bs/kolbot/libs/common/Config.js b/d2bs/kolbot/libs/common/Config.js index e37ac6497..f6b108583 100644 --- a/d2bs/kolbot/libs/common/Config.js +++ b/d2bs/kolbot/libs/common/Config.js @@ -23,7 +23,7 @@ var Config = { if (CustomConfig.hasOwnProperty(n)) { if (CustomConfig[n].indexOf(me.profile) > -1) { if (notify) { - print("�c2Loading custom config: �c9" + n + ".js"); + print("ÿc2Loading custom config: ÿc9" + n + ".js"); } configFilename = n + ".js"; @@ -57,22 +57,32 @@ var Config = { } } - if (!FileTools.exists("libs/config/" + configFilename)) { + if (FileTools.exists("libs/config/" + configFilename)) { + try { + if (!include("config/" + configFilename)) { + throw new Error(); + } + } catch (e1) { + throw new Error("Failed to load character config."); + } + } else { if (notify) { - print("�c1" + classes[me.classid] + "." + me.charname + ".js not found!"); // Use the primary format - print("�c1Loading default config."); + print("ÿc1" + classes[me.classid] + "." + me.charname + ".js not found!"); // Use the primary format + print("ÿc1Loading default config."); } - try { - include("config/" + classes[me.classid] + ".js"); - } catch (e) { - throw new Error("Failed to load default config."); + // Try to find default config + if (!FileTools.exists("libs/config/" + classes[me.classid] + ".js")) { + D2Bot.printToConsole("Not going well? Read the wiki: https://github.com/kolton/d2bot-with-kolbot/wiki"); + throw new Error("ÿc1Default config not found. \nÿc9 Try reading the kolbot wiki."); } - } else { + try { - include("config/" + configFilename); - } catch (e1) { - throw new Error("Failed to load character config."); + if (!include("config/" + classes[me.classid] + ".js")) { + throw new Error(); + } + } catch (e) { + throw new Error("ÿc1Failed to load default config."); } } @@ -80,18 +90,18 @@ var Config = { LoadConfig.call(); } catch (e2) { if (notify) { - print("�c8Error in " + e2.fileName.substring(e2.fileName.lastIndexOf("\\") + 1, e2.fileName.length) + "(line " + e2.lineNumber + "): " + e2.message); + print("ÿc8Error in " + e2.fileName.substring(e2.fileName.lastIndexOf("\\") + 1, e2.fileName.length) + "(line " + e2.lineNumber + "): " + e2.message); throw new Error("Config.init: Error in character config."); } } - - try { - if (Config.AutoBuild.Enabled === true && !isIncluded("common/AutoBuild.js") && include("common/AutoBuild.js")) { + + try { + if (Config.AutoBuild.Enabled === true && !isIncluded("common/AutoBuild.js") && include("common/AutoBuild.js")) { AutoBuild.initialize(); } } catch (e3) { - print("�c8Error in libs/common/AutoBuild.js (AutoBuild system is not active!)"); + print("ÿc8Error in libs/common/AutoBuild.js (AutoBuild system is not active!)"); print(e3.toSource()); } }, @@ -121,12 +131,19 @@ var Config = { TownMP: 0, // General + AutoMap: false, LastMessage: "", UseMerc: false, MercWatch: false, LowGold: 0, StashGold: 0, FieldID: false, + DroppedItemsAnnounce: { + Enable: false, + Quality: [], + LogToOOG: false, + OOGQuality: [] + }, CainID: { Enable: false, MinGold: 0, @@ -144,12 +161,15 @@ var Config = { DeathMessages: [], Congratulations: [], ShitList: false, + UnpartyShitlisted: false, Leader: "", QuitList: [], + QuitListMode: 0, HPBuffer: 0, MPBuffer: 0, RejuvBuffer: 0, PickRange: 40, + MakeRoom: true, FastPick: false, OpenChests: false, PickitFiles: [], @@ -190,6 +210,7 @@ var Config = { FBR: 0, IAS: 0, PacketCasting: 0, + WaypointMenu: false, // Anti-hostile AntiHostile: false, @@ -202,6 +223,11 @@ var Config = { StopOnDClone: false, SoJWaitTime: 0, KillDclone: false, + DCloneQuit: false, + + // Experimental + FastParty: false, + AutoEquip: false, // Attack specific Dodge: false, @@ -209,6 +235,7 @@ var Config = { DodgeHP: 100, AttackSkill: [], LowManaSkill: [], + CustomAttack: {}, TeleStomp: false, ClearType: false, ClearPath: false, @@ -219,6 +246,7 @@ var Config = { SummonValkyrie: false, // Sorceress specific + UseTelekinesis: false, CastStatic: false, StaticList: [], @@ -235,6 +263,7 @@ var Config = { // Paladin speficic Redemption: [0, 0], + Charge: false, Vigor: false, AvoidDolls: false, @@ -353,7 +382,9 @@ var Config = { }, DiabloHelper: { Wait: 120, - Entrance: false + Entrance: false, + SkipIfBaal: false, + SkipTP: false }, BattleOrders: { Mode: 0, @@ -380,7 +411,9 @@ var Config = { }, ShopBot: { ScanIDs: [], - ShopNPC: "anya" + ShopNPC: "anya", + CycleDelay: 0, + QuitOnMatch: false }, Coldworm: { KillBeetleburst: false, @@ -435,7 +468,13 @@ var Config = { AreaList: [] }, Rusher: { - WaitPlayerCount: 0 + WaitPlayerCount: 0, + Radament: false, + LamEsen: false, + Izual: false, + Shenk: false, + Anya: false, + LastRun: "" }, Rushee: { Quester: false, diff --git a/d2bs/kolbot/libs/common/Cubing.js b/d2bs/kolbot/libs/common/Cubing.js index 1b984e15a..44ca26814 100644 --- a/d2bs/kolbot/libs/common/Cubing.js +++ b/d2bs/kolbot/libs/common/Cubing.js @@ -88,7 +88,11 @@ var Recipe = { HighRare: 51 }, Rune: 52, - Token: 53 + Token: 53, + LowToNorm: { + Armor: 54, + Weapon: 55 + } }; var Cubing = { @@ -142,6 +146,11 @@ var Cubing = { }, getCube: function () { + // Don't activate from townchicken + if (getScript(true).name === "tools\\townchicken.js") { + return false; + } + var i, cube, chest; Pather.useWaypoint(57, true); @@ -341,16 +350,20 @@ var Cubing = { this.recipes.push({Ingredients: [Config.Recipes[i][1], 617, 621, 576], Index: Recipe.Unique.Weapon.ToExceptional, Ethereal: Config.Recipes[i][2]}); break; - case Recipe.Unique.Weapon.ToElite: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 626, 630, 576], Index: Recipe.Unique.Weapon.ToElite, Ethereal: Config.Recipes[i][2]}); + case Recipe.Unique.Weapon.ToElite: // Ladder only + if (me.ladder) { + this.recipes.push({Ingredients: [Config.Recipes[i][1], 626, 630, 576], Index: Recipe.Unique.Weapon.ToElite, Ethereal: Config.Recipes[i][2]}); + } break; case Recipe.Unique.Armor.ToExceptional: this.recipes.push({Ingredients: [Config.Recipes[i][1], 616, 622, 586], Index: Recipe.Unique.Armor.ToExceptional, Ethereal: Config.Recipes[i][2]}); break; - case Recipe.Unique.Armor.ToElite: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 629, 627, 586], Index: Recipe.Unique.Armor.ToElite, Ethereal: Config.Recipes[i][2]}); + case Recipe.Unique.Armor.ToElite: // Ladder only + if (me.ladder) { + this.recipes.push({Ingredients: [Config.Recipes[i][1], 629, 627, 586], Index: Recipe.Unique.Armor.ToElite, Ethereal: Config.Recipes[i][2]}); + } break; case Recipe.Rare.Weapon.ToExceptional: @@ -394,7 +407,15 @@ var Cubing = { break; case Recipe.Reroll.HighRare: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 601, 522], Index: Recipe.Reroll.HighRare}); + this.recipes.push({Ingredients: [Config.Recipes[i][1], 601, 522], Index: Recipe.Reroll.HighRare, Enabled: false}); + + break; + case Recipe.LowToNorm.Weapon: + this.recipes.push({Ingredients: [Config.Recipes[i][1], 611, "cgem"], Index: Recipe.LowToNorm.Weapon}); + + break; + case Recipe.LowToNorm.Armor: + this.recipes.push({Ingredients: [Config.Recipes[i][1], 610, "cgem"], Index: Recipe.LowToNorm.Armor}); break; case Recipe.Rune: @@ -411,96 +432,134 @@ var Cubing = { this.recipes.push({Ingredients: [Config.Recipes[i][1], Config.Recipes[i][1], Config.Recipes[i][1]], Index: Recipe.Rune, AlwaysEnabled: true}); break; - case 619: // thul + case 619: // thul->amn this.recipes.push({Ingredients: [619, 619, 619, 562], Index: Recipe.Rune}); break; - case 620: // amn + case 620: // amn->sol this.recipes.push({Ingredients: [620, 620, 620, 557], Index: Recipe.Rune}); break; - case 621: // sol + case 621: // sol->shael this.recipes.push({Ingredients: [621, 621, 621, 567], Index: Recipe.Rune}); break; - case 622: // shael + case 622: // shael->dol this.recipes.push({Ingredients: [622, 622, 622, 577], Index: Recipe.Rune}); break; - case 623: // dol - this.recipes.push({Ingredients: [623, 623, 623, 572], Index: Recipe.Rune}); + case 623: // dol->hel + if (me.ladder) { + this.recipes.push({Ingredients: [623, 623, 623, 572], Index: Recipe.Rune}); + } break; - case 624: // hel - this.recipes.push({Ingredients: [624, 624, 624, 582], Index: Recipe.Rune}); + case 624: // hel->io + if (me.ladder) { + this.recipes.push({Ingredients: [624, 624, 624, 582], Index: Recipe.Rune}); + } break; - case 625: // io - this.recipes.push({Ingredients: [625, 625, 625, 563], Index: Recipe.Rune}); + case 625: // io->lum + if (me.ladder) { + this.recipes.push({Ingredients: [625, 625, 625, 563], Index: Recipe.Rune}); + } break; - case 626: // lum - this.recipes.push({Ingredients: [626, 626, 626, 558], Index: Recipe.Rune}); + case 626: // lum->ko + if (me.ladder) { + this.recipes.push({Ingredients: [626, 626, 626, 558], Index: Recipe.Rune}); + } break; - case 627: // ko - this.recipes.push({Ingredients: [627, 627, 627, 568], Index: Recipe.Rune}); + case 627: // ko->fal + if (me.ladder) { + this.recipes.push({Ingredients: [627, 627, 627, 568], Index: Recipe.Rune}); + } break; - case 628: // fal - this.recipes.push({Ingredients: [628, 628, 628, 578], Index: Recipe.Rune}); + case 628: // fal->lem + if (me.ladder) { + this.recipes.push({Ingredients: [628, 628, 628, 578], Index: Recipe.Rune}); + } break; - case 629: // lem - this.recipes.push({Ingredients: [629, 629, 629, 573], Index: Recipe.Rune}); + case 629: // lem->pul + if (me.ladder) { + this.recipes.push({Ingredients: [629, 629, 629, 573], Index: Recipe.Rune}); + } break; - case 630: // pul - this.recipes.push({Ingredients: [630, 630, 583], Index: Recipe.Rune}); + case 630: // pul->um + if (me.ladder) { + this.recipes.push({Ingredients: [630, 630, 583], Index: Recipe.Rune}); + } break; - case 631: // um - this.recipes.push({Ingredients: [631, 631, 564], Index: Recipe.Rune}); + case 631: // um->mal + if (me.ladder) { + this.recipes.push({Ingredients: [631, 631, 564], Index: Recipe.Rune}); + } break; - case 632: // mal - this.recipes.push({Ingredients: [632, 632, 559], Index: Recipe.Rune}); + case 632: // mal->ist + if (me.ladder) { + this.recipes.push({Ingredients: [632, 632, 559], Index: Recipe.Rune}); + } break; - case 633: // ist - this.recipes.push({Ingredients: [633, 633, 569], Index: Recipe.Rune}); + case 633: // ist->gul + if (me.ladder) { + this.recipes.push({Ingredients: [633, 633, 569], Index: Recipe.Rune}); + } break; - case 634: // gul - this.recipes.push({Ingredients: [634, 634, 579], Index: Recipe.Rune}); + case 634: // gul->vex + if (me.ladder) { + this.recipes.push({Ingredients: [634, 634, 579], Index: Recipe.Rune}); + } break; - case 635: // vex - this.recipes.push({Ingredients: [635, 635, 574], Index: Recipe.Rune}); + case 635: // vex->ohm + if (me.ladder) { + this.recipes.push({Ingredients: [635, 635, 574], Index: Recipe.Rune}); + } break; - case 636: // ohm - this.recipes.push({Ingredients: [636, 636, 584], Index: Recipe.Rune}); + case 636: // ohm->lo + if (me.ladder) { + this.recipes.push({Ingredients: [636, 636, 584], Index: Recipe.Rune}); + } break; - case 637: // lo - this.recipes.push({Ingredients: [637, 637, 565], Index: Recipe.Rune}); + case 637: // lo->sur + if (me.ladder) { + this.recipes.push({Ingredients: [637, 637, 565], Index: Recipe.Rune}); + } break; - case 638: // sur - this.recipes.push({Ingredients: [638, 638, 560], Index: Recipe.Rune}); + case 638: // sur->ber + if (me.ladder) { + this.recipes.push({Ingredients: [638, 638, 560], Index: Recipe.Rune}); + } break; - case 639: // ber - this.recipes.push({Ingredients: [639, 639, 570], Index: Recipe.Rune}); + case 639: // ber->jah + if (me.ladder) { + this.recipes.push({Ingredients: [639, 639, 570], Index: Recipe.Rune}); + } break; - case 640: // jah - this.recipes.push({Ingredients: [640, 640, 580], Index: Recipe.Rune}); + case 640: // jah->cham + if (me.ladder) { + this.recipes.push({Ingredients: [640, 640, 580], Index: Recipe.Rune}); + } break; - case 641: // cham - this.recipes.push({Ingredients: [641, 641, 575], Index: Recipe.Rune}); + case 641: // cham->zod + if (me.ladder) { + this.recipes.push({Ingredients: [641, 641, 575], Index: Recipe.Rune}); + } break; } @@ -521,6 +580,8 @@ var Cubing = { buildLists: function () { var i, j, k, items; + CraftingSystem.checkSubrecipes(); + this.validIngredients = []; this.neededIngredients = []; items = me.findItems(-1, 0); @@ -533,6 +594,7 @@ IngredientLoop: for (j = 0; j < this.recipes[i].Ingredients.length; j += 1) { for (k = 0; k < items.length; k += 1) { if (((this.recipes[i].Ingredients[j] === "pgem" && this.gemList.indexOf(items[k].classid) > -1) || + (this.recipes[i].Ingredients[j] === "cgem" && [557, 562, 567, 572, 577, 582, 597].indexOf(items[k].classid) > -1) || items[k].classid === this.recipes[i].Ingredients[j]) && this.validItem(items[k], this.recipes[i])) { // push the item's info into the valid ingredients array. this will be used to find items when checking recipes @@ -634,10 +696,11 @@ IngredientLoop: for (i = 0; i < recipe.Ingredients.length; i += 1) { for (j = 0; j < this.validIngredients.length; j += 1) { - if (usedGids.indexOf(this.validIngredients[j].gid) === -1 && - (this.validIngredients[j].classid === recipe.Ingredients[i] || (recipe.Ingredients[i] === "pgem" && - this.gemList.indexOf(this.validIngredients[j].classid) > -1)) - ) { + if (usedGids.indexOf(this.validIngredients[j].gid) === -1 && ( + this.validIngredients[j].classid === recipe.Ingredients[i] || + (recipe.Ingredients[i] === "pgem" && this.gemList.indexOf(this.validIngredients[j].classid) > -1) || + (recipe.Ingredients[i] === "cgem" && [557, 562, 567, 572, 577, 582, 597].indexOf(this.validIngredients[j].classid) > -1) + )) { item = me.getItem(this.validIngredients[j].classid, -1, this.validIngredients[j].gid); if (item && this.validItem(item, recipe)) { // 26.11.2012. check if the item actually belongs to the given recipe @@ -722,7 +785,7 @@ IngredientLoop: } // Excluded items - if (Runewords.validGids.indexOf(unit.gid) > -1) { + if (Runewords.validGids.indexOf(unit.gid) > -1 || CraftingSystem.validGids.indexOf(unit.gid) > -1) { return false; } @@ -817,11 +880,21 @@ IngredientLoop: } if (recipe.Index === Recipe.Reroll.HighRare) { - if (unit.quality === 6 && NTIP.CheckItem(unit) === 0) { + if (recipe.Ingredients[0] === unit.classid && unit.quality === 6 && NTIP.CheckItem(unit) === 0) { + recipe.Enabled = true; + return true; } - if (unit.itemType === 10 && unit.getStat(77) && !Storage.Inventory.IsLocked(unit, Config.Inventory)) { + if (recipe.Enabled && recipe.Ingredients[2] === unit.classid && unit.itemType === 10 && unit.getStat(77) && !Storage.Inventory.IsLocked(unit, Config.Inventory)) { + return true; + } + + return false; + } + + if (recipe.Index === Recipe.LowToNorm.Armor || recipe.Index === Recipe.LowToNorm.Weapon) { + if (unit.quality === 1 && NTIP.CheckItem(unit) === 0) { return true; } @@ -895,6 +968,10 @@ IngredientLoop: Misc.itemLogger("Cubing Kept", items[j]); Misc.logItem("Cubing Kept", items[j], result.line); + break; + case 5: // Crafting System + CraftingSystem.update(items[j]); + break; } } @@ -922,7 +999,7 @@ IngredientLoop: var item; if (me.itemoncursor) { - item = getUnit(4, -1, 4); + item = getUnit(100); if (item) { if (Storage.Inventory.CanFit(item) && Storage.Inventory.MoveTo(item)) { @@ -954,6 +1031,10 @@ IngredientLoop: return false; } + if (getUIFlag(0x1A)) { + return true; + } + for (i = 0; i < 3; i += 1) { cube.interact(); @@ -988,6 +1069,8 @@ IngredientLoop: while (items.length) { if (Storage.Inventory.CanFit(items[0])) { Storage.Inventory.MoveTo(items[0]); + } else if (Storage.Stash.CanFit(items[0])) { + Storage.Stash.MoveTo(items[0]); } else { return false; } diff --git a/d2bs/kolbot/libs/common/Loader.js b/d2bs/kolbot/libs/common/Loader.js index 999389444..7ccbdbf2e 100644 --- a/d2bs/kolbot/libs/common/Loader.js +++ b/d2bs/kolbot/libs/common/Loader.js @@ -92,51 +92,53 @@ var Loader = { throw new Error("You don't have any valid scripts in bots folder."); } -ScriptLoop: for (i in Scripts) { - if (Scripts.hasOwnProperty(i) && this.scriptList.indexOf(i) > -1) { - if (!!Scripts[i]) { - if (!include("bots/" + i + ".js")) { - Misc.errorReport("Failed to include script: " + i); - } + if (Scripts.hasOwnProperty(i)) { + if (this.scriptList.indexOf(i) > -1) { + if (!!Scripts[i]) { + if (!include("bots/" + i + ".js")) { + Misc.errorReport("Failed to include script: " + i); + } - if (isIncluded("bots/" + i + ".js")) { - try { - reconfiguration = typeof Scripts[i] === 'object'; + if (isIncluded("bots/" + i + ".js")) { + try { + reconfiguration = typeof Scripts[i] === 'object'; - if (typeof (global[i]) === "function") { - if (i !== "Test" && i !== "Follower") { - townCheck = Town.goToTown(); - } else { - townCheck = true; - } + if (typeof (global[i]) === "function") { + if (i !== "Test" && i !== "Follower") { + townCheck = Town.goToTown(); + } else { + townCheck = true; + } - if (townCheck) { - print("ÿc2Starting script: ÿc9" + i); - //scriptBroadcast(JSON.stringify({currScript: i})); + if (townCheck) { + print("ÿc2Starting script: ÿc9" + i); + //scriptBroadcast(JSON.stringify({currScript: i})); + Messaging.sendToScript("tools/toolsthread.js", JSON.stringify({currScript: i})); - if (reconfiguration) { - print("ÿc2Copying Config properties from " + i + " object."); - this.copy(Scripts[i], Config); - } + if (reconfiguration) { + print("ÿc2Copying Config properties from " + i + " object."); + this.copy(Scripts[i], Config); + } - global[i](); + global[i](); - if (reconfiguration) { - print("ÿc2Reverting back unmodified config properties."); - this.copy(unmodifiedConfig, Config); + if (reconfiguration) { + print("ÿc2Reverting back unmodified config properties."); + this.copy(unmodifiedConfig, Config); + } } + } else { + throw new Error("Invalid script function name"); } - } else { - throw new Error("Invalid script function name"); + } catch (error) { + Misc.errorReport(error, i); } - } catch (error) { - Misc.errorReport(error, i); } } + } else { + Misc.errorReport("ÿc1Script " + i + " doesn't exist."); } - } else { - Misc.errorReport("ÿc1Script " + i + " doesn't exist."); } } } diff --git a/d2bs/kolbot/libs/common/Misc.js b/d2bs/kolbot/libs/common/Misc.js index 74e093c4a..fbae9204b 100644 --- a/d2bs/kolbot/libs/common/Misc.js +++ b/d2bs/kolbot/libs/common/Misc.js @@ -5,6 +5,215 @@ */ var Skill = { + usePvpRange: false, + + getRange: function (skillId) { + switch (skillId) { + case 0: // Normal Attack + return Attack.usingBow() ? 20 : 3; + case 10: // Jab + case 14: // Power Strike + case 19: // Impale + case 30: // Fend + case 34: // Lightning Strike + case 73: // Poison Dagger + case 96: // Sacrifice + case 97: // Smite + case 106: // Zeal + case 112: // Blessed Hammer + case 116: // Conversion + case 126: // Bash + case 133: // Double Swing + case 139: // Stun + case 144: // Concentrate + case 147: // Frenzy + case 152: // Berserk + case 232: // Feral Rage + case 233: // Maul + case 238: // Rabies + case 239: // Fire Claws + case 242: // Hunger + case 248: // Fury + case 255: // Dragon Talon + case 260: // Dragon Claw + case 270: // Dragon Tail + return 3; + case 146: // Battle Cry + case 154: // War Cry + return 4; + case 44: // Frost Nova + case 240: // Twister + case 245: // Tornado + case 500: // Summoner + return 5; + case 38: // Charged Bolt + return 6; + case 48: // Nova + case 151: // Whirlwind + return 7; + case 92: // Poison Nova + return 8; + case 101: // Holy Bolt + case 107: // Charge + case 130: // Howl + case 132: // Leap + case 225: // Firestorm + case 229: // Molten Boulder + case 230: // Arctic Blast + case 243: // Shock Wave + return 10; + case 64: // Frozen Orb + case 67: // Teeth + case 234: // Fissure + case 244: // Volcano + case 251: // Fire Blast + case 256: // Shock Web + case 257: // Blade Sentinel + case 266: // Blade Fury + return 15; + case 121: // Fist of the Heavens + case 253: // Psychic Hammer + case 275: // Dragon Flight + return 20; + // Variable range + case 42: // Static Field + if (me.gametype === 1) { + return Math.floor((me.getSkill(42, 1) + 4) * 2 / 3); + } + + return 20; + case 49: // Lightning + case 84: // Bone Spear + case 93: // Bone Spirit + if (this.usePvpRange) { + return 40; + } + + return 15; + case 24: // Charged Strike + case 47: + case 51: + case 53: + case 56: + case 59: + case 273: // Mind Blast + if (this.usePvpRange) { + return 40; + } + + return 20; + } + + // Every other skill + if (this.usePvpRange) { + return 40; + } + + return 20; + }, + + getHand: function (skillId) { + switch (skillId) { + case 6: + case 7: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 29: + case 30: + case 31: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 41: + case 45: + case 47: + case 49: + case 53: + case 55: + case 61: + case 63: + case 64: + case 65: + case 67: + case 73: + case 79: + case 84: + case 89: + case 93: + case 101: + case 107: + case 111: + case 112: + case 121: + case 132: + case 140: + case 143: + case 151: + case 225: + case 229: + case 230: + case 240: + case 243: + case 245: + case 251: + case 254: + case 256: + case 257: + case 259: + case 263: + case 265: + case 266: + case 269: + case 274: + case 275: + return 1; + case 0: // Normal Attack + case 96: // Sacrifice + case 97: // Smite + case 106: // Zeal + case 116: // Conversion + case 126: // Bash + case 133: // Double Swing + case 139: // Stun + case 144: // Concentrate + case 147: // Frenzy + case 152: // Berserk + case 232: // Feral Rage + case 233: // Maul + case 238: // Rabies + case 239: // Fire Claws + case 242: // Hunger + case 248: // Fury + case 255: // Dragon Talon + case 260: // Dragon Claw + case 270: // Dragon Tail + return 2; // Shift bypass + } + + // Every other skill + return 0; + }, + charges: [], // Cast a skill on self, Unit or coords @@ -23,8 +232,9 @@ var Skill = { // No mana to cast if (this.getManaCost(skillId) > me.mp) { - if (Config.AttackSkill.indexOf(skillId) > -1 || skillId === 42) { - delay(200); + // Maybe delay on ALL skills that we don't have enough mana for? + if (Config.AttackSkill.concat([42, 54]).concat(Config.LowManaSkill).indexOf(skillId) > -1) { + delay(300); } return false; @@ -56,18 +266,18 @@ var Skill = { switch (typeof x) { case "number": Packet.castSkill(hand, x, y); - delay(300); + delay(250); break; case "object": Packet.unitCast(hand, x); - delay(300); + delay(250); break; } } else { switch (hand) { - case 0: // Right hand + case 0: // Right hand + No Shift clickType = 3; shift = 0; @@ -81,6 +291,11 @@ var Skill = { clickType = 0; shift = 0; + break; + case 3: // Right hand + Shift + clickType = 3; + shift = 1; + break; } @@ -116,6 +331,10 @@ MainLoop: if (this.isTimed(skillId)) { // account for lag, state 121 doesn't kick in immediately for (i = 0; i < 10; i += 1) { + if ([4, 9].indexOf(me.mode) > -1) { + break; + } + if (me.getState(121)) { break; } @@ -129,21 +348,28 @@ MainLoop: // Put a skill on desired slot setSkill: function (skillId, hand) { - if (!me.getSkill(skillId, 1)) { - return false; + // Check if the skill is already set + if (me.getSkill(hand === 0 ? 2 : 3) === skillId) { + return true; } - if (this.isCharge(skillId)) { + if (!me.getSkill(skillId, 1)) { return false; } - if (hand === undefined) { + if (hand === undefined || hand === 3) { hand = 0; } - // Check if the skill is already set - if (me.getSkill(hand === 0 ? 2 : 3) === skillId) { - return true; + var charge = this.getCharge(skillId); + + if (!!charge) { + // charge.charges is a cached value from Attack.getCharges + /*if (charge.charges > 0 && me.setSkill(skillId, hand, charge.unit)) { + return true; + }*/ + + return false; } if (me.setSkill(skillId, hand)) { @@ -154,12 +380,12 @@ MainLoop: }, // Charged skill - isCharge: function (skillId) { + getCharge: function (skillId) { var i; for (i = 0; i < this.charges.length; i += 1) { if (this.charges[i].skill === skillId && me.getSkill(skillId, 0) === this.charges[i].level && me.getSkill(skillId, 0) === me.getSkill(skillId, 1)) { - return true; + return this.charges[i]; } } @@ -178,7 +404,7 @@ MainLoop: } // Can be cast by both - if ([1, 221, 222, 226, 227, 231, 236, 237, 239, 241, 242, 246, 247, 249].indexOf(skillId) > -1) { + if ([0, 1, 221, 222, 226, 227, 231, 236, 237, 239, 241, 242, 246, 247, 249].indexOf(skillId) > -1) { return true; } @@ -200,38 +426,125 @@ MainLoop: return [32, 40, 43, 50, 52, 58, 60, 68, 75, 85, 94, 117, 221, 222, 226, 227, 235, 236, 237, 246, 247, 258, 267, 268, 277, 278, 279].indexOf(skillId) > -1; }, + manaCostList: {}, + // Get mana cost of the skill (mBot) getManaCost: function (skillId) { + if (skillId < 6) { + return 0; + } + + if (this.manaCostList.hasOwnProperty(skillId)) { + return this.manaCostList[skillId]; + } + var skillLvl = me.getSkill(skillId, 1), effectiveShift = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024], lvlmana = getBaseStat(3, skillId, "lvlmana") === 65535 ? -1 : getBaseStat(3, skillId, "lvlmana"), // Correction for skills that need less mana with levels (kolton) ret = Math.max((getBaseStat(3, skillId, "mana") + lvlmana * (skillLvl - 1)) * (effectiveShift[getBaseStat(3, skillId, "manashift")] / 256), getBaseStat(3, skillId, "minmana")); + if (!this.manaCostList.hasOwnProperty(skillId)) { + this.manaCostList[skillId] = ret; + } + return ret; } }; -var Items = { - // Equips an item and throws away the old equipped item - equip: function (unit) { - if (unit.type !== 4) { - throw new Error("Items.equp: Unit must be an item"); +var Item = { + hasTier: function (item) { + return Config.AutoEquip && NTIP.GetTier(item) > 0; + }, + + canEquip: function (item) { + if (item.type !== 4) { // Not an item + return false; } - if (!unit.getFlag(0x10)) { // Unid item + if (!item.getFlag(0x10)) { // Unid item return false; } - if (unit.getStat(92) > me.getStat(12)) { // Higher level req item + if (item.getStat(92) > me.getStat(12) || item.dexreq > me.getStat(2) || item.strreq > me.getStat(0)) { // Higher requirements + return false; + } + + return true; + }, + + // Equips an item and throws away the old equipped item + equip: function (item, bodyLoc) { + if (!this.canEquip(item)) { return false; } - var i, bodyLoc; + // Already equipped in the right slot + if (item.mode === 1 && item.bodylocation === bodyLoc) { + return true; + } - switch (unit.itemType) { + var i, cursorItem; + + if (item.location === 7) { + if (!Town.openStash()) { + return false; + } + } + + for (i = 0; i < 3; i += 1) { + if (item.toCursor()) { + clickItem(0, bodyLoc); + delay(me.ping * 2 + 500); + + if (item.bodylocation === bodyLoc) { + if (getCursorType() === 3) { + //Misc.click(0, 0, me); + + cursorItem = getUnit(100); + + if (cursorItem && Pickit.checkItem(cursorItem).result > 0 && (NTIP.GetTier(cursorItem) < 1 || NTIP.GetTier(cursorItem) > 99)) { + if (Storage.Inventory.CanFit(cursorItem)) { + Storage.Inventory.MoveTo(cursorItem); + } + } + } + + return true; + } + } + } + + return false; + }, + + getEquippedItem: function (bodyLoc) { + var item = me.getItem(); + + if (item) { + do { + if (item.bodylocation === bodyLoc) { + return { + classid: item.classid, + tier: NTIP.GetTier(item) + }; + } + } while (item.getNext()); + } + + // Don't have anything equipped in there + return { + classid: -1, + tier: -1 + }; + }, + + getBodyLoc: function (item) { + var bodyLoc; + + switch (item.itemType) { case 2: // Shield case 70: // Auric Shields - bodyLoc = [4, 5]; + bodyLoc = 5; break; case 3: // Armor @@ -240,7 +553,7 @@ var Items = { break; case 5: // Arrows case 6: // Bolts - bodyLoc = [4, 5]; + bodyLoc = 5; break; case 10: // Ring @@ -293,34 +606,120 @@ var Items = { case 86: // case 87: // case 88: // - bodyLoc = [4, 5]; + bodyLoc = 4; break; default: - throw new Error("Items.equip: Bad item type"); + return false; } - if (typeof bodyLoc === "object") { - // Temporary - bodyLoc = bodyLoc[0]; + if (typeof bodyLoc === "number") { + bodyLoc = [bodyLoc]; } - for (i = 0; i < 3; i += 1) { - if (unit.toCursor()) { - clickItem(0, bodyLoc); - delay(me.ping * 2 + 500); + return bodyLoc; + }, - if (unit.bodylocation === bodyLoc) { - if (getCursorType() === 3) { - Misc.click(0, 0, me); - } + autoEquipCheck: function (item) { + if (!Config.AutoEquip) { + return true; + } + var i, + tier = NTIP.GetTier(item), + bodyLoc = this.getBodyLoc(item); + + if (tier > 0 && bodyLoc) { + for (i = 0; i < bodyLoc.length; i += 1) { + // Low tier items shouldn't be kept if they can't be equipped + if (tier > this.getEquippedItem(bodyLoc[i]).tier && (this.canEquip(item) || !item.getFlag(0x10))) { return true; } } } - return false; + // Sell/ignore low tier items, keep high tier + if (tier > 0 && tier < 100) { + return false; + } + + return true; + }, + + // returns true if the item should be kept+logged, false if not + autoEquip: function () { + if (!Config.AutoEquip) { + return true; + } + + var i, j, tier, bodyLoc, tome, gid, + items = me.findItems(-1, 0); + + if (!items) { + return false; + } + + function sortEq(a, b) { + if (Item.canEquip(a)) { + return -1; + } + + if (Item.canEquip(b)) { + return 1; + } + + return 0; + } + + me.cancel(); + + // Remove items without tier + for (i = 0; i < items.length; i += 1) { + if (NTIP.GetTier(items[i]) === 0) { + items.splice(i, 1); + + i -= 1; + } + } + + while (items.length > 0) { + items.sort(sortEq); + + tier = NTIP.GetTier(items[0]); + bodyLoc = this.getBodyLoc(items[0]); + + if (tier > 0 && bodyLoc) { + for (j = 0; j < bodyLoc.length; j += 1) { + if ([3, 7].indexOf(items[0].location) > -1 && tier > this.getEquippedItem(bodyLoc[j]).tier && this.getEquippedItem(bodyLoc[j]).classid !== 174) { // khalim's will adjustment + if (!items[0].getFlag(0x10)) { // unid + tome = me.findItem(519, 0, 3); + + if (tome && tome.getStat(70) > 0) { + if (items[0].location === 7) { + Town.openStash(); + } + + Town.identifyItem(items[0], tome); + } + } + + gid = items[0].gid; + + print(items[0].name); + + if (this.equip(items[0], bodyLoc[j])) { + Misc.logItem("Equipped", me.getItem(-1, -1, gid)); + } + + break; + } + } + } + + items.shift(); + } + + return true; } }; @@ -405,6 +804,36 @@ var Misc = { return false; }, + // Get number of players within getUnit distance + getNearbyPlayerCount: function () { + var count = 0, + player = getUnit(0); + + if (player) { + do { + if (!player.dead) { + count += 1; + } + } while (player.getNext()); + } + + return count; + }, + + // Get total number of players in game + getPlayerCount: function () { + var count = 0, + party = getParty(); + + if (party) { + do { + count += 1; + } while (party.getNext()); + } + + return count; + }, + // Open a chest Unit openChest: function (unit) { // Skip invalid and Countess chests @@ -425,8 +854,9 @@ var Misc = { var i, tick; for (i = 0; i < 3; i += 1) { - if (Pather.moveTo(unit.x + 1, unit.y, 0)) { - Misc.click(0, 0, unit); + if (Pather.moveTo(unit.x + 1, unit.y + 2, 3) && getDistance(me, unit.x + 1, unit.y + 2) < 5) { + //Misc.click(0, 0, unit); + sendPacket(1, 0x13, 4, unit.type, 4, unit.gid); } tick = getTickCount(); @@ -461,7 +891,7 @@ var Misc = { } coords = []; - presetUnits = getPresetUnits(area); + presetUnits = getPresetUnits(area, 2); if (!chestIds) { chestIds = [ @@ -488,7 +918,7 @@ var Misc = { while (coords.length) { coords.sort(Sort.units); - Pather.moveToUnit(coords[0], 2, 0); + Pather.moveToUnit(coords[0], 1, 2); this.openChests(20); for (i = 0; i < coords.length; i += 1) { @@ -536,7 +966,7 @@ var Misc = { unit = unitList.shift(); - if (unit && this.openChest(unit)) { + if (unit && (Pather.useTeleport || !checkCollision(me, unit, 0x4)) && this.openChest(unit)) { Pickit.pickItems(); } } @@ -552,7 +982,7 @@ var Misc = { } if (!range) { - range = 25; + range = Pather.useTeleport ? 25 : 15; } var i, j, shrine, @@ -623,7 +1053,7 @@ var Misc = { // Get the shrine if we have no active state or to refresh current state or if the shrine has no state // Don't override shrine state with a lesser priority shrine if (index === -1 || i <= index || this.shrineStates[i] === 0) { - if (shrineList[j].objtype === Config.ScanShrines[i]) { + if (shrineList[j].objtype === Config.ScanShrines[i] && (Pather.useTeleport || !checkCollision(me, shrineList[j], 0x4))) { this.getShrine(shrineList[j]); // Gem shrine - pick gem @@ -711,7 +1141,13 @@ var Misc = { var i, desc, stringColor = ""; - desc = unit.description.split("\n"); + desc = unit.description; + + if (!desc) { + return ""; + } + + desc = desc.split("\n"); // Lines are normally in reverse. Add color tags if needed and reverse order. for (i = 0; i < desc.length; i += 1) { @@ -806,8 +1242,10 @@ var Misc = { return tempArray; }, + useItemLog: true, // Might be a bit dirty + itemLogger: function (action, unit, text) { - if (!Config.ItemInfo) { + if (!Config.ItemInfo || !this.useItemLog) { return false; } @@ -852,6 +1290,10 @@ var Misc = { // Log kept item stats in the manager. logItem: function (action, unit, keptLine) { + if (!this.useItemLog) { + return false; + } + var i, lastArea, code, desc, sock, itemObj, color = -1, name = unit.fname.split("\n").reverse().join(" ").replace(/ÿc[0-9!"+<;.*]/, "").trim(); @@ -1136,44 +1578,46 @@ var Misc = { if (Config.TownCheck && !me.inTown) { try { - for (i = 0; i < 4; i += 1) { - if (Config.BeltColumn[i] === "hp" && Config.MinColumn[i] > 0) { - potion = me.getItem(-1, 2); // belt item - - if (potion) { - do { - if (potion.code.indexOf("hp") > -1) { - needhp = false; - - break; - } - } while (potion.getNext()); - } + if (me.gold > 1000) { + for (i = 0; i < 4; i += 1) { + if (Config.BeltColumn[i] === "hp" && Config.MinColumn[i] > 0) { + potion = me.getItem(-1, 2); // belt item + + if (potion) { + do { + if (potion.code.indexOf("hp") > -1) { + needhp = false; + + break; + } + } while (potion.getNext()); + } - if (needhp) { - print("We need healing potions"); + if (needhp) { + print("We need healing potions"); - check = true; + check = true; + } } - } - if (Config.BeltColumn[i] === "mp" && Config.MinColumn[i] > 0) { - potion = me.getItem(-1, 2); // belt item + if (Config.BeltColumn[i] === "mp" && Config.MinColumn[i] > 0) { + potion = me.getItem(-1, 2); // belt item - if (potion) { - do { - if (potion.code.indexOf("mp") > -1) { - needmp = false; + if (potion) { + do { + if (potion.code.indexOf("mp") > -1) { + needmp = false; - break; - } - } while (potion.getNext()); - } + break; + } + } while (potion.getNext()); + } - if (needmp) { - print("We need mana potions"); + if (needmp) { + print("We need mana potions"); - check = true; + check = true; + } } } } @@ -1207,7 +1651,7 @@ var Misc = { } var item, - unit = getUnit(0, name); + unit = getUnit(-1, name); if (!unit) { print("player not found"); @@ -1219,7 +1663,7 @@ var Misc = { if (item) { do { - this.logItem(name, item); + this.logItem(unit.name, item); } while (item.getNext()); } @@ -1297,7 +1741,8 @@ MainLoop: // Report script errors to logs/ScriptErrorLog.txt errorReport: function (error, script) { - var h, m, s, date, msg, oogmsg, filemsg, source; + var i, h, m, s, date, msg, oogmsg, filemsg, source, stack, + stackLog = ""; date = new Date(); h = date.getHours(); @@ -1313,6 +1758,32 @@ MainLoop: msg = "ÿc1Error in ÿc0" + script + " ÿc1(" + source + " line ÿc1" + error.lineNumber + "): ÿc1" + error.message; oogmsg = " Error in " + script + " (" + source + " #" + error.lineNumber + ") " + error.message + " (Area: " + me.area + ", Ping:" + me.ping + ", Game: " + me.gamename + ")"; filemsg = "[" + (h < 10 ? "0" + h : h) + ":" + (m < 10 ? "0" + m : m) + ":" + (s < 10 ? "0" + s : s) + "] <" + me.profile + "> " + msg.replace(/ÿc[0-9!"+<;.*]/gi, "") + "\n"; + + if (error.hasOwnProperty("stack")) { + stack = error.stack; + + if (stack) { + stack = stack.split("\n"); + + if (stack && typeof stack === "object") { + stack.reverse(); + } + + for (i = 0; i < stack.length; i += 1) { + if (stack[i]) { + stackLog += stack[i].substr(0, stack[i].indexOf("@") + 1) + stack[i].substr(stack[i].lastIndexOf("\\") + 1, stack[i].length - 1); + + if (i < stack.length - 1) { + stackLog += ", "; + } + } + } + } + } + + if (stackLog) { + filemsg += "Stack: " + stackLog + "\n"; + } } if (this.errorConsolePrint) { @@ -1551,15 +2022,21 @@ var Packet = { var i, j; - for (i = 0; i < 3; i += 1) { + for (i = 0; i < 5; i += 1) { if (getDistance(me, unit) > 5) { Pather.moveToUnit(unit); } - sendPacket(1, 0x13, 4, 1, 4, unit.gid); + if (i > 0) { + Packet.flash(me.gid); + } + + if (!getUIFlag(0x08)) { + sendPacket(1, 0x13, 4, 1, 4, unit.gid); + } for (j = 0; j < 40; j += 1) { - if (j % 8 === 0) { + if (j > 0 && j % 8 === 0 && !getUIFlag(0x08)) { me.cancel(); delay(300); sendPacket(1, 0x13, 4, 1, 4, unit.gid); @@ -1587,7 +2064,7 @@ var Packet = { return true; } - var i, tick, + var i, gamble = mode === "Gamble"; if (this.openMenu(unit)) { @@ -1722,6 +2199,62 @@ CursorLoop: return false; }, + itemToCursor: function (item) { + var i, tick; + + if (me.itemoncursor) { // Something already on cursor + if (getUnit(100).gid === item.gid) { // Return true if the item is already on cursor + return true; + } + + this.dropItem(getUnit(100)); // If another item is on cursor, drop it + } + + for (i = 0; i < 15; i += 1) { + if (item.mode === 1) { // equipped + sendPacket(1, 0x1c, 2, item.bodylocation); + } else { + sendPacket(1, 0x19, 4, item.gid); + } + + tick = getTickCount(); + + while (getTickCount() - tick < Math.max(500, me.ping * 2 + 200)) { + if (me.itemoncursor) { + return true; + } + + delay(10); + } + } + + return false; + }, + + dropItem: function (item) { + var i, tick; + + if (!this.itemToCursor(item)) { + return false; + } + + for (i = 0; i < 15; i += 1) { + sendPacket(1, 0x17, 4, item.gid); + + tick = getTickCount(); + + while (getTickCount() - tick < Math.max(500, me.ping * 2 + 200)) { + if (!me.itemoncursor) { + return true; + } + + delay(10); + } + } + + return false; + }, + castSkill: function (hand, wX, wY) { hand = (hand === 0) ? 0x0c : 0x05; sendPacket(1, hand, 2, wX, 2, wY); @@ -1736,11 +2269,35 @@ CursorLoop: sendPacket(1, 0x59, 4, npc.type, 4, npc.gid, 4, dwX, 4, dwY); }, - teleWalk: function (wX, wY) { - sendPacket(1, 0x5f, 2, wX, 2, wY); - delay(200); - sendPacket(1, 0x4b, 4, me.type, 4, me.gid); - delay(200); + teleWalk: function (x, y, maxDist) { + var i; + + if (maxDist === undefined) { + maxDist = 5; + } + + if (!this.telewalkTick) { + this.telewalkTick = 0; + } + + if (getDistance(me, x, y) > 10 && getTickCount() - this.telewalkTick > 3000 && Attack.validSpot(x, y)) { + for (i = 0; i < 5; i += 1) { + sendPacket(1, 0x5f, 2, x + rand(-1, 1), 2, y + rand(-1, 1)); + delay(me.ping + 1); + sendPacket(1, 0x4b, 4, me.type, 4, me.gid); + delay(me.ping + 1); + + if (getDistance(me, x, y) < maxDist) { + delay(200); + + return true; + } + } + + this.telewalkTick = getTickCount(); + } + + return false; }, flash: function (gid) { @@ -1752,4 +2309,100 @@ CursorLoop: getPacket(1, 0x1d, 1, stat, 1, value); } } +}; + +var Messaging = { + sendToScript: function (name, msg) { + var script = getScript(name); + + if (script && script.running) { + script.send(msg); + + return true; + } + + return false; + }, + + sendToProfile: function (profileName, mode, message, getResponse) { + var response; + + function copyDataEvent(mode2, msg) { + if (mode2 === mode) { + var obj; + + try { + obj = JSON.parse(msg); + } catch (e) { + return false; + } + + if (obj.hasOwnProperty("sender") && obj.sender === profileName) { + response = Misc.copy(obj); + } + + return true; + } + + return false; + } + + if (getResponse) { + addEventListener("copydata", copyDataEvent); + } + + if (!sendCopyData(null, profileName, mode, JSON.stringify({message: message, sender: me.profile}))) { + //print("sendToProfile: failed to get response from " + profileName); + + if (getResponse) { + removeEventListener("copydata", copyDataEvent); + } + + return false; + } + + if (getResponse) { + delay(200); + removeEventListener("copydata", copyDataEvent); + + if (!!response) { + return response; + } + + return false; + } + + return true; + } +}; + +var Events = { + // gamepacket + gamePacket: function (bytes) { + var temp; + + switch (bytes[0]) { + // Block movement after using TP/WP/Exit + case 0x0D: // Player Stop + // This can mess up death screen so disable for characters that are allowed to die + if (Config.LifeChicken > 0) { + return true; + } + + break; + // Block poison skills that might crash the client + case 0x4C: // Cast skill on target + case 0x4D: // Cast skill on coords + temp = Number("0x" + bytes[7].toString(16) + bytes[6].toString(16)); + + // Match Poison Javelin, Plague Javelin or Poison Nova + if (temp && [15, 25, 92].indexOf(temp) > -1) { + return true; + } + + break; + } + + return false; + } }; \ No newline at end of file diff --git a/d2bs/kolbot/libs/common/Pather.js b/d2bs/kolbot/libs/common/Pather.js index c7456dd85..521e8a55b 100644 --- a/d2bs/kolbot/libs/common/Pather.js +++ b/d2bs/kolbot/libs/common/Pather.js @@ -32,18 +32,16 @@ var NodeAction = { if ((typeof Config.ClearPath === "number" || typeof Config.ClearPath === "object") && arg.clearPath === false) { switch (typeof Config.ClearPath) { case "number": - monList = Attack.getMob(-1, Config.ClearPath, 30); + Attack.clear(30, Config.ClearPath); break; case "object": - monList = Attack.getMob(-1, Config.ClearPath.Spectype, Config.ClearPath.Range); + if (!Config.ClearPath.hasOwnProperty("Areas") || Config.ClearPath.Areas.length === 0 || Config.ClearPath.Areas.indexOf(me.area) > -1) { + Attack.clear(Config.ClearPath.Range, Config.ClearPath.Spectype); + } break; } - - if (monList) { - Attack.clearList(monList); - } } if (arg.clearPath !== false) { @@ -53,37 +51,86 @@ var NodeAction = { // Open chests while pathing popChests: function () { - if (Config.OpenChests > 0) { - Misc.openChests(15); + if (!!Config.OpenChests) { + Misc.openChests(20); } }, // Scan shrines while pathing getShrines: function () { - if (Config.ScanShrines && Config.ScanShrines.length) { + if (!!Config.ScanShrines && Config.ScanShrines.length > 0) { Misc.scanShrines(); } } }; +var PathDebug = { + hooks: [], + enableHooks: false, + + drawPath: function (path) { + if (!this.enableHooks) { + return; + } + + this.removeHooks(); + + var i; + + if (path.length < 2) { + return; + } + + for (i = 0; i < path.length - 1; i += 1) { + this.hooks.push(new Line(path[i].x, path[i].y, path[i + 1].x, path[i + 1].y, 0x84, true)); + } + }, + + removeHooks: function () { + var i; + + for (i = 0; i < this.hooks.length; i += 1) { + this.hooks[i].remove(); + } + + this.hooks = []; + }, + + coordsInPath: function (path, x, y) { + var i; + + for (i = 0; i < path.length; i += 1) { + if (getDistance(x, y, path[i].x, path[i].y) < 5) { + return true; + } + } + + return false; + } +}; + var Pather = { teleport: true, walkDistance: 10, teleDistance: 40, - cancelFlags: [0x01, 0x02, 0x04, 0x08, 0x14, 0x16, 0x0c, 0x0f, 0x17], + cancelFlags: [0x01, 0x02, 0x04, 0x08, 0x14, 0x16, 0x0c, 0x0f, 0x17, 0x19, 0x1A], wpAreas: [1, 3, 4, 5, 6, 27, 29, 32, 35, 40, 48, 42, 57, 43, 44, 52, 74, 46, 75, 76, 77, 78, 79, 80, 81, 83, 101, 103, 106, 107, 109, 111, 112, 113, 115, 123, 117, 118, 129], recursion: true, + /* + Pather.moveTo(x, y, retry, clearPath, pop); + x - the x coord to move to + y - the y coord to move to + retry - number of attempts before aborting + clearPath - kill monsters while moving + pop - remove last node + */ moveTo: function (x, y, retry, clearPath, pop) { - while (!me.gameReady) { - delay(100); - } - if (me.dead) { // Abort if dead return false; } - var i, path, adjustedNode, + var i, path, adjustedNode, cleared, node = {x: x, y: y}, fail = 0; @@ -117,8 +164,8 @@ var Pather = { pop = false; } - this.useTeleport = this.teleport && !me.getState(139) && !me.getState(140) && !me.inTown - && ((me.classid === 1 && me.getSkill(54, 1)) || me.getStat(97, 54)); + this.useTeleport = this.teleport && !me.getState(139) && !me.getState(140) && !me.inTown && + ((me.classid === 1 && me.getSkill(54, 1)) || me.getStat(97, 54)); // Teleport without calling getPath if the spot is close enough if (this.useTeleport && getDistance(me, x, y) <= this.teleDistance) { @@ -132,26 +179,20 @@ var Pather = { return this.walkTo(x, y); } - while (!me.area) { - delay(40); - } - path = getPath(me.area, x, y, me.x, me.y, this.useTeleport ? 1 : 0, this.useTeleport ? ([62, 63, 64].indexOf(me.area) > -1 ? 30 : this.teleDistance) : this.walkDistance); if (!path) { throw new Error("moveTo: Failed to generate path."); } - while (!me.gameReady) { - delay(40); - } - path.reverse(); if (pop) { path.pop(); } + PathDebug.drawPath(path); + if (this.useTeleport && Config.TeleSwitch) { Misc.teleSwitch(); } @@ -183,9 +224,30 @@ var Pather = { } } - if (!(this.useTeleport ? this.teleportTo(node.x, node.y) : this.walkTo(node.x, node.y))) { + if (this.useTeleport ? this.teleportTo(node.x, node.y) : this.walkTo(node.x, node.y, (fail > 0 || me.inTown) ? 2 : 4)) { + if (!me.inTown) { + if (this.recursion) { + this.recursion = false; + + NodeAction.go({clearPath: clearPath}); + + if (getDistance(me, node.x, node.y) > 5) { + this.moveTo(node.x, node.y); + } + + this.recursion = true; + } + + Misc.townCheck(); + } + } else { if (fail > 0 && !this.useTeleport && !me.inTown) { - Attack.clear(5); + // Don't go berserk on longer paths + if (!cleared) { + Attack.clear(5); + + cleared = true; + } if (fail > 1 && me.getSkill(143, 1)) { Skill.cast(143, 0, node.x, node.y); @@ -193,7 +255,7 @@ var Pather = { } // Reduce node distance in new path - path = getPath(me.area, x, y, me.x, me.y, this.useTeleport ? 1 : 0, this.useTeleport ? rand(20, 30) : 10); + path = getPath(me.area, x, y, me.x, me.y, this.useTeleport ? 1 : 0, this.useTeleport ? rand(25, 35) : rand(10, 15)); fail += 1; if (!path) { @@ -201,28 +263,17 @@ var Pather = { } path.reverse(); + PathDebug.drawPath(path); - print("move retry " + fail); - } - - if (fail > 0 && fail >= retry) { - break; - } - - if (!me.inTown && path.length > 1) { // Don't use NodeAction or TownCheck on last node - if (this.recursion) { - this.recursion = false; - - NodeAction.go({clearPath: clearPath}); + if (pop) { + path.pop(); + } - if (getDistance(me, node.x, node.y) > 4) { - this.moveTo(node.x, node.y); - } + print("move retry " + fail); - this.recursion = true; + if (fail > 0 && fail >= retry) { + break; } - - Misc.townCheck(); } } @@ -233,12 +284,23 @@ var Pather = { Precast.weaponSwitch(Misc.oldSwitch); } + PathDebug.removeHooks(); + return getDistance(me, node.x, node.y) < 5; }, - teleportTo: function (x, y) { + /* + Pather.teleportTo(x, y); + x - the x coord to teleport to + y - the y coord to teleport to + */ + teleportTo: function (x, y, maxRange) { var i, tick; + if (maxRange === undefined) { + maxRange = 5; + } + MainLoop: for (i = 0; i < 3; i += 1) { if (Config.PacketCasting) { @@ -251,17 +313,23 @@ MainLoop: tick = getTickCount(); while (getTickCount() - tick < Math.max(500, me.ping * 2 + 200)) { - if (getDistance(me.x, me.y, x, y) < 5) { + if (getDistance(me.x, me.y, x, y) < maxRange) { return true; } - delay(40); + delay(10); } } return false; }, + /* + Pather.walkTo(x, y); + x - the x coord to walk to + y - the y coord to walk to + minDist - minimal distance from x/y before returning true + */ walkTo: function (x, y, minDist) { while (!me.gameReady) { delay(100); @@ -271,31 +339,37 @@ MainLoop: minDist = me.inTown ? 2 : 4; } - var i, angle, angles, nTimer, whereToClick, + var i, angle, angles, nTimer, whereToClick, tick, nFail = 0, attemptCount = 0; - if (me.runwalk === 1 && me.stamina / me.staminamax * 100 <= 20) { - me.runwalk = 0; - } - - if (me.runwalk === 0 && me.stamina / me.staminamax * 100 >= 50) { - me.runwalk = 1; - } + // Stamina handler and Charge + if (!me.inTown && !me.dead) { + if (me.runwalk === 1 && me.stamina / me.staminamax * 100 <= 20) { + me.runwalk = 0; + } - // Charge! - if (me.classid === 3 && !me.dead && !me.inTown && me.mp >= 9 && getDistance(me.x, me.y, x, y) > 8 && Skill.setSkill(107, 1)) { - if (Config.Vigor) { - Skill.setSkill(115, 0); + if (me.runwalk === 0 && me.stamina / me.staminamax * 100 >= 50) { + me.runwalk = 1; } - Misc.click(0, 1, x, y); + if (Config.Charge && me.classid === 3 && me.mp >= 9 && getDistance(me.x, me.y, x, y) > 8 && Skill.setSkill(107, 1)) { + if (Config.Vigor) { + Skill.setSkill(115, 0); + } + + Misc.click(0, 1, x, y); - while (me.mode !== 1 && me.mode !== 5 && !me.dead) { - delay(40); + while (me.mode !== 1 && me.mode !== 5 && !me.dead) { + delay(40); + } } } + if (me.inTown && me.runwalk === 0) { + me.runwalk = 1; + } + while (getDistance(me.x, me.y, x, y) > minDist && !me.dead) { if (me.classid === 3 && Config.Vigor) { Skill.setSkill(115, 0); @@ -305,8 +379,7 @@ MainLoop: return true; } - //Misc.click(0, 0, x, y); - me.move(x, y); + Misc.click(0, 0, x, y); attemptCount += 1; nTimer = getTickCount(); @@ -328,14 +401,20 @@ ModeLoop: angles = [Math.PI / 2, -Math.PI / 2]; for (i = 0; i < angles.length; i += 1) { + // TODO: might need rework into getnearestwalkable whereToClick = { x: Math.round(Math.cos(angle + angles[i]) * 5 + me.x), y: Math.round(Math.sin(angle + angles[i]) * 5 + me.y) }; if (Attack.validSpot(whereToClick.x, whereToClick.y)) { - //Misc.click(0, 0, whereToClick.x, whereToClick.y); - me.move(whereToClick.x, whereToClick.y); + Misc.click(0, 0, whereToClick.x, whereToClick.y); + + tick = getTickCount(); + + while (getDistance(me, whereToClick) > 2 && getTickCount() - tick < 1000) { + delay(40); + } break; } @@ -344,24 +423,27 @@ ModeLoop: break ModeLoop; } - delay(40); + delay(10); } // Wait until we're done walking - idle or dead while (getDistance(me.x, me.y, x, y) > minDist && me.mode !== 1 && me.mode !== 5 && !me.dead) { - delay(40); + delay(10); } if (attemptCount >= 3) { return false; } - - delay(5); } return !me.dead && getDistance(me.x, me.y, x, y) <= minDist; }, + /* + Pather.openDoors(x, y); + x - the x coord of the node close to the door + y - the y coord of the node close to the door + */ openDoors: function (x, y) { if (me.inTown) { return false; @@ -394,18 +476,22 @@ ModeLoop: } while (door.getNext()); } - // TODO: Monsta doors (Barricaded) + // DO: Monsta doors (Barricaded) return false; }, /* - This function moves to an existing unit or object with x, y properties. It can also accept a preset unit. - If you want to go to a preset unit based on its area, type and id, use Pather.moveToPreset(). + Pather.moveToUnit(unit, offX, offY, clearPath, pop); + unit - a valid Unit or PresetUnit object + offX - offset from unit's x coord + offY - offset from unit's x coord + clearPath - kill monsters while moving + pop - remove last node */ - moveToUnit: function (unit, offX, offY, clearPath, pop) { // Maybe use range instead of XY offset - this.useTeleport = this.teleport && !me.getState(139) && !me.getState(140) && !me.inTown - && ((me.classid === 1 && me.getSkill(54, 1)) || me.getStat(97, 54)); + moveToUnit: function (unit, offX, offY, clearPath, pop) { + this.useTeleport = this.teleport && !me.getState(139) && !me.getState(140) && !me.inTown && + ((me.classid === 1 && me.getSkill(54, 1)) || me.getStat(97, 54)); if (offX === undefined) { offX = 0; @@ -436,11 +522,18 @@ ModeLoop: this.moveTo(unit.x + offX, unit.y + offY, 0, clearPath, true); } - return this.moveTo(unit.x + offX, unit.y + offY, this.useTeleport ? 3 : 0, clearPath, pop); + return this.moveTo(unit.x + offX, unit.y + offY, this.useTeleport && unit.type && unit.type === 1 ? 3 : 0, clearPath, pop); }, /* - This function finds the preset unit based on its area, unitType and unitId and then moves to it. + Pather.moveToPreset(area, unitType, unitId, offX, offY, clearPath, pop); + area - area of the preset unit + unitType - type of the preset unit + unitId - preset unit id + offX - offset from unit's x coord + offY - offset from unit's x coord + clearPath - kill monsters while moving + pop - remove last node */ moveToPreset: function (area, unitType, unitId, offX, offY, clearPath, pop) { if (area === undefined || unitType === undefined || unitId === undefined) { @@ -472,9 +565,14 @@ ModeLoop: return this.moveTo(presetUnit.roomx * 5 + presetUnit.x + offX, presetUnit.roomy * 5 + presetUnit.y + offY, 3, clearPath, pop); }, - // moveToExit can take a single area or an array of areas as the first argument + /* + Pather.moveToExit(targetArea, use, clearPath); + targetArea - area id or array of area ids to move to + use - enter target area or last area in the array + clearPath - kill monsters while moving + */ moveToExit: function (targetArea, use, clearPath) { - var i, j, area, exits, targetRoom, dest, + var i, j, area, exits, targetRoom, dest, currExit, areas = []; if (targetArea instanceof Array) { @@ -486,7 +584,7 @@ ModeLoop: for (i = 0; i < areas.length; i += 1) { area = getArea(); - if (typeof area !== "object") { + if (!area) { throw new Error("moveToExit: error in getArea()"); } @@ -497,14 +595,22 @@ ModeLoop: } for (j = 0; j < exits.length; j += 1) { - if (exits[j].target === areas[i]) { - dest = this.getNearestWalkable(exits[j].x, exits[j].y, 5, 1); + currExit = { + x: exits[j].x, + y: exits[j].y, + type: exits[j].type, + target: exits[j].target, + tileid: exits[j].tileid + }; + + if (currExit.target === areas[i]) { + dest = this.getNearestWalkable(currExit.x, currExit.y, 5, 1); if (!dest) { return false; } - if (!Pather.moveTo(dest[0], dest[1], 3, clearPath)) { + if (!this.moveTo(dest[0], dest[1], 3, clearPath)) { return false; } @@ -512,7 +618,7 @@ ModeLoop: In that case we must use the exit before the last area. */ if (use || i < areas.length - 1) { - switch (exits[j].type) { + switch (currExit.type) { case 1: // walk through targetRoom = this.getNearestRoom(areas[i]); @@ -525,7 +631,7 @@ ModeLoop: break; case 2: // stairs - if (!this.useUnit(5, exits[j].tileid, areas[i])) { + if (!this.useUnit(5, currExit.tileid, areas[i])) { return false; } @@ -545,6 +651,10 @@ ModeLoop: return true; }, + /* + Pather.getNearestRoom(area); + area - the id of area to search for the room nearest to the player character + */ getNearestRoom: function (area) { var i, x, y, dist, room, minDist = 10000; @@ -584,6 +694,12 @@ ModeLoop: return [x, y]; }, + /* + Pather.useUnit(type, id, targetArea); + type - type of the unit to use + id - id of the unit to use + targetArea - area id of where the unit leads to + */ useUnit: function (type, id, targetArea) { var i, tick, unit, preArea = me.area; @@ -607,14 +723,14 @@ ModeLoop: this.moveToUnit(unit); } - delay(200); - Misc.click(0, 0, unit); + delay(300); + sendPacket(1, 0x13, 4, unit.type, 4, unit.gid); tick = getTickCount(); while (getTickCount() - tick < 3000) { - if ((targetArea === null && me.area !== preArea) || me.area === targetArea) { - delay(200); + if ((!targetArea && me.area !== preArea) || me.area === targetArea) { + delay(100); return true; } @@ -625,14 +741,18 @@ ModeLoop: this.moveTo(me.x + 3 * rand(-1, 1), me.y + 3 * rand(-1, 1)); } - return false; + return targetArea ? me.area === targetArea : me.area !== preArea; }, - // If there is no check, it will try to take the waypoint directly, without opening the waypoint screen + /* + Pather.moveTo(targetArea, check); + targetArea - id of the area to enter + check - force the waypoint menu + */ useWaypoint: function useWaypoint(targetArea, check) { switch (targetArea) { case undefined: - throw new Error("useWaypoint: Invalid targetArea parameter"); + throw new Error("useWaypoint: Invalid targetArea parameter: " + targetArea); case null: case "random": check = true; @@ -650,13 +770,11 @@ ModeLoop: break; } - var i, tick, wp, timer; - - timer = getTickCount(); + var i, tick, wp; for (i = 0; i < 12; i += 1) { - if (me.area === targetArea) { - return true; + if (me.area === targetArea || me.dead) { + break; } if (me.inTown) { @@ -666,12 +784,15 @@ ModeLoop: wp = getUnit(2, "waypoint"); if (wp && wp.area === me.area) { - if (!me.inTown && getDistance(me, wp) > 5) { + if (!me.inTown && getDistance(me, wp) > 7) { this.moveToUnit(wp); } - if (check) { - this.moveToUnit(wp); + if (check || Config.WaypointMenu) { + if (getDistance(me, wp) > 5) { + this.moveToUnit(wp); + } + Misc.click(0, 0, wp); tick = getTickCount(); @@ -716,98 +837,98 @@ ModeLoop: delay(10); } - } - wp.interact(targetArea); + if (!getUIFlag(0x14)) { + print("waypoint retry " + (i + 1)); + this.moveTo(me.x + rand(-5, 5), me.y + rand(-5, 5)); + Packet.flash(me.gid); - tick = getTickCount(); - - while (getTickCount() - tick < Math.max(Math.round((i + 1) * 1000 / (i / 5 + 1)), me.ping * 2)) { - while (!me.gameReady || !me.area) { - delay(100); + continue; } + } - if (me.area === targetArea) { - delay(200); + if (!check || getUIFlag(0x14)) { + delay(200); + wp.interact(targetArea); - return true; - } + tick = getTickCount(); - delay(10); - } + while (getTickCount() - tick < Math.max(Math.round((i + 1) * 1000 / (i / 5 + 1)), me.ping * 2)) { + if (me.area === targetArea) { + delay(100); - if (me.inTown) { - Misc.click(0, 0, me.x + rand(-1, 1) * 4, me.y + rand(-1, 1) * 4); // In case of client/server desync + return true; + } - if (i > 2) { - Town.move("stash"); + delay(10); } - Town.move("waypoint"); - } else { - this.moveToUnit(wp); + me.cancel(); // In case lag causes the wp menu to stay open } - if (i > 1) { // Activate check if we fail direct interact twice - Packet.flash(me.gid); + Packet.flash(me.gid); + if (i > 1) { // Activate check if we fail direct interact twice check = true; } - - me.cancel(); // In case lag causes the wp menu to stay open } else { Packet.flash(me.gid); } - delay(me.ping + 1); + delay(200 + me.ping); + } + + if (me.area === targetArea) { + return true; } throw new Error("useWaypoint: Failed to use waypoint"); }, + /* + Pather.makePortal(use); + use - use the portal that was made + */ makePortal: function (use) { if (me.inTown) { return true; } - var i, portal, oldPortal, oldGid, tick, - tpTome = me.findItem("tbk", 0, 3); + var i, portal, oldPortal, oldGid, tick, tpTome; - if (!tpTome) { - throw new Error("makePortal: No TP tomes."); - } + for (i = 0; i < 5; i += 1) { + if (me.dead) { + break; + } - if (!tpTome.getStat(70)) { - throw new Error("makePortal: No scrolls."); - } + tpTome = me.findItem("tbk", 0, 3); - /* Check for old portal - - Because this function is fast, if there's player's portal already nearby, it's possible it will try to use that one without this check. - */ - oldPortal = getUnit(2, "portal"); + if (!tpTome) { + throw new Error("makePortal: No TP tomes."); + } - if (oldPortal) { - do { - if (oldPortal.getParent() === me.name) { - oldGid = oldPortal.gid; + if (!tpTome.getStat(70)) { + throw new Error("makePortal: No scrolls."); + } - break; - } - } while (oldPortal.getNext()); - } + oldPortal = getUnit(2, "portal"); - for (i = 0; i < 5; i += 1) { - if (me.dead) { - break; + if (oldPortal) { + do { + if (oldPortal.getParent() === me.name) { + oldGid = oldPortal.gid; + + break; + } + } while (oldPortal.getNext()); } - Packet.flash(me.gid); tpTome.interact(); tick = getTickCount(); MainLoop: - while (getTickCount() - tick < 2000) { + while (getTickCount() - tick < Math.max(500 + i * 100, me.ping * 2 + 100)) { portal = getUnit(2, "portal"); if (portal) { @@ -820,22 +941,33 @@ MainLoop: break MainLoop; // don't spam usePortal } else { - return portal; + return copyUnit(portal); } } } while (portal.getNext()); } - delay(50); + delay(10); } - delay(250); + Packet.flash(me.gid); + delay(200 + me.ping); } return false; }, + /* + Pather.usePortal(targetArea, owner, unit); + targetArea - id of the area the portal leads to + owner - name of the portal's owner + unit - use existing portal unit + */ usePortal: function (targetArea, owner, unit) { + if (targetArea && me.area === targetArea) { + return true; + } + me.cancel(); var i, tick, portal, useTK, @@ -843,11 +975,7 @@ MainLoop: for (i = 0; i < 10; i += 1) { if (me.dead) { - return false; - } - - if (me.area !== preArea) { - return true; + break; } if (i > 0 && owner && me.inTown) { @@ -869,7 +997,7 @@ MainLoop: Skill.cast(43, 0, portal); } else { - if (getDistance(me, portal) > (i > 3 ? 3 : 6)) { + if (getDistance(me, portal) > 5) { this.moveToUnit(portal); } @@ -881,13 +1009,13 @@ MainLoop: } } - if (portal.mode !== 2 && portal.classid === 298) { // Arcane Sanctuary + if (portal.classid === 298 && portal.mode !== 2) { // Portal to/from Arcane Misc.click(0, 0, portal); tick = getTickCount(); while (getTickCount() - tick < 2000) { - if (portal.mode === 2) { + if (portal.mode === 2 || me.area === 74) { break; } @@ -898,12 +1026,8 @@ MainLoop: tick = getTickCount(); while (getTickCount() - tick < Math.max(Math.round((i + 1) * 1000 / (i / 5 + 1)), me.ping * 2)) { - while (!me.area || !me.gameReady) { - delay(100); - } - if (me.area !== preArea) { - delay(200); + delay(100); return true; } @@ -920,12 +1044,17 @@ MainLoop: Packet.flash(me.gid); } - delay(me.ping + 1); + delay(200 + me.ping); } - return false; + return targetArea ? me.area === targetArea : me.area !== preArea; }, + /* + Pather.getPortal(targetArea, owner, unit); + targetArea - id of the area the portal leads to + owner - name of the portal's owner + */ getPortal: function (targetArea, owner) { var portal = getUnit(2, "portal"); @@ -959,7 +1088,15 @@ MainLoop: return false; }, - getNearestWalkable: function (x, y, range, step, coll) { + /* + Pather.moveTo(x, y, range, step, coll); + x - the starting x coord + y - the starting y coord + range - maximum allowed range from the starting coords + step - distance between each checked dot on the grid + coll - collision flag to avoid + */ + getNearestWalkable: function (x, y, range, step, coll, size) { if (!step) { step = 1; } @@ -973,7 +1110,7 @@ MainLoop: result = false; // Check if the original spot is valid - if (this.checkSpot(x, y, coll)) { + if (this.checkSpot(x, y, coll, false, size)) { result = [x, y]; } @@ -983,7 +1120,7 @@ MainLoop: for (j = -distance; j <= distance; j += 1) { // Check outer layer only (skip previously checked) if (Math.abs(i) >= Math.abs(distance) || Math.abs(j) >= Math.abs(distance)) { - if (this.checkSpot(x + i, y + j, coll)) { + if (this.checkSpot(x + i, y + j, coll, false, size)) { result = [x + i, y + j]; break MainLoop; @@ -1000,15 +1137,26 @@ MainLoop: return result; }, - checkSpot: function (x, y, coll, cacheOnly) { + /* + Pather.moveTo(x, y, coll, cacheOnly); + x - the x coord to check + y - the y coord to check + coll - collision flag to search for + cacheOnly - use only cached room data + */ + checkSpot: function (x, y, coll, cacheOnly, size) { var dx, dy, value; if (coll === undefined) { coll = 0x1; } - for (dx = -1; dx <= 1; dx += 1) { - for (dy = -1; dy <= 1; dy += 1) { + if (!size) { + size = 1; + } + + for (dx = -size; dx <= size; dx += 1) { + for (dy = -size; dy <= size; dy += 1) { if (Math.abs(dx) !== Math.abs(dy)) { value = CollMap.getColl(x + dx, y + dy, cacheOnly); @@ -1022,6 +1170,10 @@ MainLoop: return true; }, + /* + Pather.accessToAct(act); + act - the act number to check for access + */ accessToAct: function (act) { switch (act) { // Act 1 is always accessible @@ -1041,7 +1193,12 @@ MainLoop: } }, - getWP: function (area) { + /* + Pather.getWP(area); + area - the id of area to get the waypoint in + clearPath - clear path + */ + getWP: function (area, clearPath) { var i, j, wp, preset, wpIDs = [119, 145, 156, 157, 237, 238, 288, 323, 324, 398, 402, 429, 494, 496, 511, 539]; @@ -1053,7 +1210,7 @@ MainLoop: preset = getPresetUnit(area, 2, wpIDs[i]); if (preset) { - this.moveToUnit(preset); + this.moveToUnit(preset, 0, 0, clearPath); wp = getUnit(2, "waypoint"); @@ -1078,6 +1235,10 @@ MainLoop: return false; }, + /* + Pather.journeyTo(area); + area - the id of area to move to + */ journeyTo: function (area) { var i, special, unit, tick, target; @@ -1138,6 +1299,8 @@ MainLoop: break; } + + delay(10); } } } @@ -1155,7 +1318,7 @@ MainLoop: } } else if (me.area === 40 && target.course[0] === 47) { // Lut Gholein -> Sewers Level 1 (use Trapdoor) this.moveToPreset(me.area, 5, 19); - this.useUnit(5, 19); + this.useUnit(5, 19, 47); } else if (me.area === 74 && target.course[0] === 46) { // Arcane Sanctuary -> Canyon of the Magi this.moveToPreset(me.area, 2, 357); @@ -1197,6 +1360,11 @@ MainLoop: plotCourse_openedWpMenu: false, + /* + Pather.plotCourse(dest, src); + dest - destination area id + src - starting area id + */ plotCourse: function (dest, src) { var node, prevArea, useWP = false, @@ -1225,8 +1393,8 @@ MainLoop: if ((me.inTown || // check wp in town ((src !== previousAreas[dest] && dest !== previousAreas[src]) && // check wp if areas aren't linked previousAreas[src] !== previousAreas[dest])) && // check wp if areas aren't linked with a common area - Pather.wpAreas.indexOf(node.from) > 0 && getWaypoint(Pather.wpAreas.indexOf(node.from)) - ) { + Pather.wpAreas.indexOf(node.from) > 0 && getWaypoint(Pather.wpAreas.indexOf(node.from)) + ) { if (node.from !== src) { useWP = true; } @@ -1273,6 +1441,11 @@ MainLoop: return {course: arr, useWP: useWP}; }, + /* + Pather.areasConnected(src, dest); + dest - destination area id + src - starting area id + */ areasConnected: function (src, dest) { if (src === 46 && dest === 74) { return false; @@ -1281,6 +1454,10 @@ MainLoop: return true; }, + /* + Pather.getAreaName(area); + area - id of the area to get the name for + */ getAreaName: function (area) { var areas = [ "None", diff --git a/d2bs/kolbot/libs/common/Pickit.js b/d2bs/kolbot/libs/common/Pickit.js index a4eba4ba1..3af2d0cdf 100644 --- a/d2bs/kolbot/libs/common/Pickit.js +++ b/d2bs/kolbot/libs/common/Pickit.js @@ -32,27 +32,49 @@ var Pickit = { var rval = NTIP.CheckItem(unit, false, true); if ((unit.classid === 617 || unit.classid === 618) && Town.repairIngredientCheck(unit)) { - return {result: 6, line: null}; + return { + result: 6, + line: null + }; + } + + if (CraftingSystem.checkItem(unit)) { + return { + result: 5, + line: null + }; } if (Cubing.checkItem(unit)) { - return {result: 2, line: null}; + return { + result: 2, + line: null + }; } if (Runewords.checkItem(unit)) { - return {result: 3, line: null}; + return { + result: 3, + line: null + }; } // If total gold is less than 10k pick up anything worth 10 gold per // square to sell in town. - if (me.getStat(14) + me.getStat(15) < Config.LowGold && rval.result === 0 && Town.ignoredItemTypes.indexOf(unit.itemType) === -1) { + if (rval.result === 0 && Town.ignoredItemTypes.indexOf(unit.itemType) === -1 && me.gold < Config.LowGold && unit.itemType !== 39) { // Gold doesn't take up room, just pick it up if (unit.classid === 523) { - return {result: 4, line: null}; + return { + result: 4, + line: null + }; } if (unit.getItemCost(1) / (unit.sizex * unit.sizey) >= 10) { - return {result: 4, line: null}; + return { + result: 4, + line: null + }; } } @@ -60,24 +82,9 @@ var Pickit = { }, pickItems: function () { - function ItemStats(unit) { - this.ilvl = unit.ilvl; - this.itemType = unit.itemType; - this.quality = unit.quality; - this.classid = unit.classid; - this.code = unit.code; - this.name = unit.name; - this.x = unit.x; - this.y = unit.y; - this.sizex = unit.sizex; // cache for CanFit - this.sizey = unit.sizey; - this.gid = unit.gid; - } - - var status, gid, item, canFit, + var status, item, canFit, needMule = false, - pickList = [], - noSpaceList = []; + pickList = []; Town.clearBelt(); @@ -94,113 +101,102 @@ var Pickit = { if (item) { do { if ((item.mode === 3 || item.mode === 5) && getDistance(me, item) <= Config.PickRange) { - pickList.push(new ItemStats(item)); + pickList.push(copyUnit(item)); } } while (item.getNext()); } - pickList.sort(this.sortItems); - while (pickList.length > 0) { if (me.dead) { return false; } - gid = pickList[0].gid; + pickList.sort(this.sortItems); - if (gid) { - item = getUnit(4, -1, -1, gid); + // Check if the item unit is still valid and if it's on ground or being dropped + if (copyUnit(pickList[0]).x !== undefined && (pickList[0].mode === 3 || pickList[0].mode === 5) && + (Pather.useTeleport || me.inTown || !checkCollision(me, pickList[0], 0x1))) { // Don't pick items behind walls/obstacles when walking + // Check if the item should be picked + status = this.checkItem(pickList[0]); - if (item && (item.mode === 3 || item.mode === 5)) { - status = this.checkItem(item); + if (status.result && this.canPick(pickList[0]) && Item.autoEquipCheck(pickList[0])) { + // Override canFit for scrolls, potions and gold + canFit = Storage.Inventory.CanFit(pickList[0]) || [4, 22, 76, 77, 78].indexOf(pickList[0].itemType) > -1; - if (status.result && this.canPick(pickList[0])) { + // Try to make room with FieldID + if (!canFit && Config.FieldID && Town.fieldID()) { canFit = Storage.Inventory.CanFit(pickList[0]) || [4, 22, 76, 77, 78].indexOf(pickList[0].itemType) > -1; - - if (canFit) { - this.pickItem(item, status.result, status.line); - } else { - noSpaceList.push(new ItemStats(item)); - } } - } - } - - pickList.shift(); - } - if (noSpaceList.length) { - print(noSpaceList.length + " item(s) can't fit."); - } + // Try to make room by selling items in town + if (!canFit) { + // Check if any of the current inventory items can be stashed or need to be identified and eventually sold to make room + if (this.canMakeRoom()) { + print("ÿc7Trying to make room for " + this.itemColor(pickList[0]) + pickList[0].name); - while (noSpaceList.length > 0) { - gid = noSpaceList[0].gid; + // Go to town and do town chores + if (Town.visitTown()) { + // Recursive check after going to town. We need to remake item list because gids can change. + // Called only if room can be made so it shouldn't error out or block anything. - if (gid) { - item = getUnit(4, -1, -1, gid); - - if (item && (item.mode === 3 || item.mode === 5)) { - status = this.checkItem(item); + return this.pickItems(); + } - if (status.result && this.canPick(noSpaceList[0])) { - canFit = Storage.Inventory.CanFit(noSpaceList[0]) || [4, 22, 76, 77, 78].indexOf(noSpaceList[0].itemType) > -1; + // Town visit failed - abort + print("ÿc7Not enough room for " + this.itemColor(pickList[0]) + pickList[0].name); - if (!canFit && Config.FieldID && Town.fieldID()) { - canFit = Storage.Inventory.CanFit(noSpaceList[0]) || [4, 22, 76, 77, 78].indexOf(noSpaceList[0].itemType) > -1; + return false; } - if (!canFit && this.canMakeRoom()) { - print("ÿc7Trying to make room for " + this.itemColor(noSpaceList[0]) + noSpaceList[0].name); - - if (!Town.visitTown()) { - print("ÿc7Not enough room for " + this.itemColor(noSpaceList[0]) + noSpaceList[0].name); + // Can't make room - trigger automule + Misc.itemLogger("No room for", pickList[0]); + print("ÿc7Not enough room for " + this.itemColor(pickList[0]) + pickList[0].name); - return false; - } - - item = getUnit(4, -1, -1, gid); - canFit = Storage.Inventory.CanFit(noSpaceList[0]) || [4, 22, 76, 77, 78].indexOf(noSpaceList[0].itemType) > -1; - } - - if (item) { - if (canFit) { - this.pickItem(item, status.result, status.line); - } else { - Misc.itemLogger("No room for", noSpaceList[0]); - print("ÿc7Not enough room for " + this.itemColor(noSpaceList[0]) + noSpaceList[0].name); + needMule = true; + } - needMule = true; - } - } + // Item can fit - pick it up + if (canFit) { + this.pickItem(pickList[0], status.result, status.line); } } } - noSpaceList.shift(); + pickList.shift(); } + // Quit current game and transfer the items to mule if (needMule && AutoMule.getInfo() && AutoMule.getInfo().hasOwnProperty("muleInfo") && AutoMule.getMuleItems().length > 0) { scriptBroadcast("mule"); - quit(); + scriptBroadcast("quit"); } return true; }, - // check if we can even free up the inventory + // Check if we can even free up the inventory canMakeRoom: function () { + if (!Config.MakeRoom) { + return false; + } + var i, items = Storage.Inventory.Compare(Config.Inventory); if (items) { for (i = 0; i < items.length; i += 1) { switch (this.checkItem(items[i]).result) { - case -1: // item needs to be identified + case -1: // Item needs to be identified + // For low level chars that can't actually get id scrolls -> prevent an infinite loop + if (me.getStat(14) + me.getStat(15) < 100) { + return false; + } + return true; case 0: break; - default: // check if a kept item can be stashed - if (Town.ignoredItemTypes.indexOf(items[i].itemType) === -1 && Storage.Stash.CanFit(items[i])) { + default: // Check if a kept item can be stashed + if (Town.canStash(items[i])) { return true; } @@ -220,7 +216,7 @@ var Pickit = { this.name = unit.name; this.color = Pickit.itemColor(unit); this.gold = unit.getStat(14); - this.useTk = me.classid === 1 && me.getSkill(43, 1) && (this.type === 4 || this.type === 22 || (this.type > 75 && this.type < 82)) && + this.useTk = Config.UseTelekinesis && me.classid === 1 && me.getSkill(43, 1) && (this.type === 4 || this.type === 22 || (this.type > 75 && this.type < 82)) && getDistance(me, unit) > 5 && getDistance(me, unit) < 20 && !checkCollision(me, unit, 0x4); this.picked = false; } @@ -259,7 +255,15 @@ MainLoop: if (stats.useTk) { Skill.cast(43, 0, item); - } else if (getDistance(me, item) < (Config.FastPick === 2 && i < 1 ? 6 : 4) || Pather.moveToUnit(item)) { + } else { + if (getDistance(me, item) > (Config.FastPick === 2 && i < 1 ? 6 : 4) || checkCollision(me, item, 0x1)) { + if (Pather.useTeleport) { + Pather.moveToUnit(item); + } else if (!Pather.moveTo(item.x, item.y, 0)) { + continue MainLoop; + } + } + if (Config.FastPick < 2) { Misc.click(0, 0, item); } else { @@ -299,6 +303,9 @@ MainLoop: delay(20); } + // TK failed, disable it + stats.useTk = false; + //print("pick retry"); } @@ -309,31 +316,42 @@ MainLoop: switch (status) { case 1: - print("ÿc7Picked up " + stats.color + stats.name + " (ilvl " + stats.ilvl + ")"); + print("ÿc7Picked up " + stats.color + stats.name + " ÿc0(ilvl " + stats.ilvl + (keptLine ? ") (" + keptLine + ")" : ")")); if (this.ignoreLog.indexOf(stats.type) === -1) { Misc.itemLogger("Kept", item); - if (["pk1", "pk2", "pk3"].indexOf(item.code) === -1 || TorchSystem.LogKeys) { - Misc.logItem("Kept", item, keptLine); + if (["pk1", "pk2", "pk3"].indexOf(item.code) > -1 && !TorchSystem.LogKeys) { + break; } + + if (["dhn", "bey", "mbr"].indexOf(item.code) > -1 && !TorchSystem.LogOrgans) { + break; + } + + Misc.logItem("Kept", item, keptLine); } break; case 2: - print("ÿc7Picked up " + stats.color + stats.name + " (ilvl " + stats.ilvl + ")" + " ÿc0(Cubing)"); + print("ÿc7Picked up " + stats.color + stats.name + " ÿc0(ilvl " + stats.ilvl + ")" + " (Cubing)"); Misc.itemLogger("Kept", item, "Cubing " + me.findItems(item.classid).length); Cubing.update(); break; case 3: - print("ÿc7Picked up " + stats.color + stats.name + " (ilvl " + stats.ilvl + ")" + " ÿc0(Runewords)"); + print("ÿc7Picked up " + stats.color + stats.name + " ÿc0(ilvl " + stats.ilvl + ")" + " (Runewords)"); Misc.itemLogger("Kept", item, "Runewords"); Runewords.update(stats.classid, gid); + break; + case 5: // Crafting System + print("ÿc7Picked up " + stats.color + stats.name + " ÿc0(ilvl " + stats.ilvl + ")" + " (Crafting System)"); + CraftingSystem.update(item); + break; default: - print("ÿc7Picked up " + stats.color + stats.name + " (ilvl " + stats.ilvl + ")"); + print("ÿc7Picked up " + stats.color + stats.name + " ÿc0(ilvl " + stats.ilvl + (keptLine ? ") (" + keptLine + ")" : ")")); break; } @@ -384,13 +402,27 @@ MainLoop: return "ÿc0"; }, - sortItems: function (unitA, unitB) { - return getDistance(me, unitA) - getDistance(me, unitB); - }, - canPick: function (unit) { var tome, charm, i, potion, needPots, buffers, pottype, myKey, key; + switch (unit.classid) { + case 92: // Staff of Kings + case 173: // Khalim's Flail + case 521: // Viper Amulet + case 546: // Jade Figurine + case 549: // Cube + case 551: // Mephisto's Soulstone + case 552: // Book of Skill + case 553: // Khalim's Eye + case 554: // Khalim's Heart + case 555: // Khalim's Brain + if (me.getItem(unit.classid)) { + return false; + } + + break; + } + switch (unit.itemType) { case 4: // Gold if (me.getStat(14) === me.getStat(12) * 10000) { // Check current gold vs max capacity (cLvl*10000) @@ -505,37 +537,23 @@ MainLoop: } } } - - if (needPots < 1) { - potion = me.getItem(-1, 2); - if (potion) { - do { - if (potion.itemType === unit.itemType) { - if (potion.classid < unit.classid) { - potion.interact(); - needPots += 1; - break; - } - } - } while (potion.getNext()); - } - } - + if (needPots < 1) { - potion = me.getItem(-1, 0); + potion = me.getItem(); + if (potion) { do { - if (potion.itemType === unit.itemType) { + if (potion.itemType === unit.itemType && ((potion.mode === 0 && potion.location === 3) || potion.mode === 2)) { if (potion.classid < unit.classid) { potion.interact(); needPots += 1; + break; } } } while (potion.getNext()); } } - if (needPots < 1) { return false; @@ -566,14 +584,44 @@ MainLoop: return check === 4; }, + // Just sort by distance for general item pickup + sortItems: function (unitA, unitB) { + return getDistance(me, unitA) - getDistance(me, unitB); + }, + + // Prioritize runes and unique items for fast pick + sortFastPickItems: function (unitA, unitB) { + if (unitA.itemType === 74 || unitA.quality === 7) { + return -1; + } + + if (unitB.itemType === 74 || unitB.quality === 7) { + return 1; + } + + return getDistance(me, unitA) - getDistance(me, unitB); + }, + fastPick: function () { - var item, gid, status; + var item, gid, status, + itemList = []; while (this.gidList.length > 0) { gid = this.gidList.shift(); item = getUnit(4, -1, -1, gid); if (item && (item.mode === 3 || item.mode === 5) && Town.ignoredItemTypes.indexOf(item.itemType) === -1 && getDistance(me, item) <= Config.PickRange) { + itemList.push(copyUnit(item)); + } + } + + while (itemList.length > 0) { + itemList.sort(this.sortFastPickItems); + + item = copyUnit(itemList.shift()); + + // Check if the item unit is still valid + if (item.x !== undefined) { status = this.checkItem(item); if (status.result && this.canPick(item) && (Storage.Inventory.CanFit(item) || [4, 22, 76, 77, 78].indexOf(item.itemType) > -1)) { diff --git a/d2bs/kolbot/libs/common/Precast.js b/d2bs/kolbot/libs/common/Precast.js index a23207a64..f859fed6a 100644 --- a/d2bs/kolbot/libs/common/Precast.js +++ b/d2bs/kolbot/libs/common/Precast.js @@ -14,6 +14,12 @@ var Precast = new function () { return true; } + if (slot === -1) { + this.BOSwitch(); + + slot = this.haveCTA; + } + var i, tick; if (slot === undefined) { @@ -29,9 +35,9 @@ var Precast = new function () { tick = getTickCount(); - while (getTickCount() - tick < 4000) { + while (getTickCount() - tick < 2000 + me.ping) { if (me.weaponswitch === slot) { - delay(me.ping + 1); + //delay(me.ping + 1); return true; } @@ -66,7 +72,7 @@ var Precast = new function () { return false; }; - + this.getBetterSlot = function (skillId) { var item, sumCurr = 0, @@ -90,6 +96,24 @@ var Precast = new function () { } while (item.getNext()); } + break; + case 52: // Enchant + sumCurr = 0; + sumSwap = 0; + item = me.getItem(); + + if (item) { + do { + if (item.bodylocation === 4 || item.bodylocation === 5) { + sumCurr += (item.getStat(127) + item.getStat(83, 1) + item.getStat(188, 8) + item.getStat(107, skillId) + item.getStat(97, skillId)); + } + + if (item.bodylocation === 11 || item.bodylocation === 12) { + sumSwap += (item.getStat(127) + item.getStat(83, 1) + item.getStat(188, 8) + item.getStat(107, skillId) + item.getStat(97, skillId)); + } + } while (item.getNext()); + } + break; } @@ -411,9 +435,16 @@ MainLoop: }; this.enchant = function () { - var unit, + var unit, swapped, + slot = this.getBetterSlot(52), chanted = []; + if (slot !== me.weaponswitch) { + swapped = true; + } + + this.weaponSwitch(slot); + // Player unit = getUnit(0); @@ -437,6 +468,10 @@ MainLoop: } while (unit.getNext()); } + if (swapped) { + this.weaponSwitch(Math.abs(slot - 1)); + } + return true; }; }; \ No newline at end of file diff --git a/d2bs/kolbot/libs/common/Prototypes.js b/d2bs/kolbot/libs/common/Prototypes.js index 030ce1d69..5691811e7 100644 --- a/d2bs/kolbot/libs/common/Prototypes.js +++ b/d2bs/kolbot/libs/common/Prototypes.js @@ -39,17 +39,25 @@ Unit.prototype.__defineGetter__("idle", throw new Error("Unit.idle: Must be used with player units."); } - return (this.mode === 1 || this.mode === 5); + return (this.mode === 1 || this.mode === 5 || this.mode === 17); // Dead is pretty idle too + }); + +Unit.prototype.__defineGetter__("gold", + function () { + return this.getStat(14) + this.getStat(15); }); // Death check Unit.prototype.__defineGetter__("dead", function () { - if (this.type > 0) { - throw new Error("Unit.dead: Must be used with player units."); + switch (this.type) { + case 0: // Player + return this.mode === 0 || this.mode === 17; + case 1: // Monster + return this.mode === 0 || this.mode === 12; + default: + return false; } - - return (this.mode === 0 || this.mode === 17); }); // Check if unit is in town @@ -74,7 +82,7 @@ Unit.prototype.__defineGetter__("attacking", throw new Error("Unit.attacking: Must be used with player units."); } - return [7, 8, 10, 11, 12, 13, 14, 15, 16, 18].indexOf(me.mode) > -1; + return [7, 8, 10, 11, 12, 13, 14, 15, 16, 18].indexOf(this.mode) > -1; }); // Open NPC menu @@ -98,25 +106,25 @@ Unit.prototype.openMenu = function (addDelay) { var i, j; for (i = 0; i < 5; i += 1) { - if (getDistance(me, this) > 3) { + if (getDistance(me, this) > 4) { Pather.moveToUnit(this); } if (i > 0) { Packet.flash(me.gid); + // delay? } - //Misc.click(0, 0, this); - this.interact(); - //sendPacket(1, 0x13, 4, 1, 4, this.gid); + if (!getUIFlag(0x08)) { + delay(100); + this.interact(); + } for (j = 0; j < 40; j += 1) { - if (j > 0 && j % 10 === 0) { + if (j > 0 && j % 10 === 0 && !getUIFlag(0x08)) { me.cancel(); delay(400); - //Misc.click(0, 0, this); this.interact(); - //sendPacket(1, 0x13, 4, 1, 4, this.gid); } if (getUIFlag(0x08)) { @@ -277,13 +285,21 @@ Unit.prototype.toCursor = function () { throw new Error("Unit.toCursor: Must be used with items."); } + if (me.itemoncursor && this.mode === 4) { + return true; + } + var i, tick; for (i = 0; i < 3; i += 1) { - if (this.mode === 1) { - clickItem(0, this.bodylocation); // fix for equipped items (cubing viper staff for example) - } else { - clickItem(0, this); + try { + if (this.mode === 1) { + clickItem(0, this.bodylocation); // fix for equipped items (cubing viper staff for example) + } else { + clickItem(0, this); + } + } catch (e) { + return false; } tick = getTickCount(); @@ -334,7 +350,7 @@ Unit.prototype.drop = function () { return false; }; -me.findItem = function (id, mode, loc) { +me.findItem = function (id, mode, loc, quality) { if (id === undefined) { id = -1; } @@ -344,28 +360,24 @@ me.findItem = function (id, mode, loc) { } if (loc === undefined) { - loc = false; + loc = -1; } - var item = me.getItem(id, mode); - - if (!item) { - return false; + if (quality === undefined) { + quality = -1; } - if (loc) { - while (item.location !== loc) { - if (!item.getNext()) { - break; - } - } + var item = me.getItem(id, mode); - if (item.location !== loc) { - return false; - } + if (item) { + do { + if ((loc === -1 || item.location === loc) && (quality === -1 || item.quality === quality)) { + return item; + } + } while (item.getNext()); } - return item; + return false; }; me.findItems = function (id, mode, loc) { @@ -520,13 +532,86 @@ Unit.prototype.getStatEx = function (id, subid) { var i, temp, rval, regex; switch (id) { + case 20: // toblock + switch (this.classid) { + case 328: // buckler + return this.getStat(20); + case 413: // preserved + case 483: // mummified + case 503: // minion + return this.getStat(20) - 3; + case 329: // small + case 414: // zombie + case 484: // fetish + case 504: // hellspawn + return this.getStat(20) - 5; + case 331: // kite + case 415: // unraveller + case 485: // sexton + case 505: // overseer + return this.getStat(20) - 8; + case 351: // spiked + case 374: // deefender + case 416: // gargoyle + case 486: // cantor + case 506: // succubus + case 408: // targe + case 478: // akaran t + return this.getStat(20) - 10; + case 330: // large + case 375: // round + case 417: // demon + case 487: // hierophant + case 507: // bloodlord + return this.getStat(20) - 12; + case 376: // scutum + return this.getStat(20) - 14; + case 409: // rondache + case 479: // akaran r + return this.getStat(20) - 15; + case 333: // goth + case 379: // ancient + return this.getStat(20) - 16; + case 397: // barbed + return this.getStat(20) - 17; + case 377: // dragon + return this.getStat(20) - 18; + case 502: // vortex + return this.getStat(20) - 19; + case 350: // bone + case 396: // grim + case 445: // luna + case 467: // blade barr + case 466: // troll + case 410: // heraldic + case 480: // protector + return this.getStat(20) - 20; + case 444: // heater + case 447: // monarch + case 411: // aerin + case 481: // gilded + case 501: // zakarum + return this.getStat(20) - 22; + case 332: // tower + case 378: // pavise + case 446: // hyperion + case 448: // aegis + case 449: // ward + return this.getStat(20) - 24; + case 412: // crown + case 482: // royal + case 500: // kurast + return this.getStat(20) - 25; + case 499: // sacred r + return this.getStat(20) - 28; + case 498: // sacred t + return this.getStat(20) - 30; + } + + break; case 21: // plusmindamage case 22: // plusmaxdamage if (subid === 1) { - if (this.mode !== 0) { - break; - } - temp = this.getStat(-1); rval = 0; @@ -555,7 +640,7 @@ Unit.prototype.getStatEx = function (id, subid) { break; case 31: // plusdefense if (subid === 0) { - if (this.mode !== 0) { + if ([0, 1].indexOf(this.mode) < 0) { break; } @@ -584,6 +669,12 @@ Unit.prototype.getStatEx = function (id, subid) { return 0; } + break; + case 57: + if (subid === 1) { + return Math.round(this.getStat(57) * this.getStat(59) / 256); + } + break; case 83: // itemaddclassskills if (subid === undefined) { @@ -638,7 +729,7 @@ Unit.prototype.getStatEx = function (id, subid) { if (this.getFlag(0x04000000)) { // Runeword switch (id) { case 16: // enhanceddefense - if (this.mode !== 0) { + if ([0, 1].indexOf(this.mode) < 0) { break; } @@ -656,7 +747,7 @@ Unit.prototype.getStatEx = function (id, subid) { return 0; case 18: // enhanceddamage - if (this.mode !== 0) { + if ([0, 1].indexOf(this.mode) < 0) { break; } @@ -806,6 +897,7 @@ Unit.prototype.getColor = function () { "Rainbow": Color.lightpurple, "Scintillating": Color.lightpurple, "Prismatic": Color.lightpurple, + "Chromatic": Color.lightpurple, "Hierophant's": Color.crystalgreen, "Berserker's": Color.crystalgreen, "Necromancer's": Color.crystalgreen, diff --git a/d2bs/kolbot/libs/common/Runewords.js b/d2bs/kolbot/libs/common/Runewords.js index 3ac8c91c3..2abac1502 100644 --- a/d2bs/kolbot/libs/common/Runewords.js +++ b/d2bs/kolbot/libs/common/Runewords.js @@ -4,6 +4,8 @@ * @desc make and reroll runewords */ +// TODO: Config.Runewords[i][0] can be false, but array methods can be used on it + var Runeword = { // 1.09 AncientsPledge: [617, 618, 616], // Ral + Ort + Tal @@ -30,6 +32,7 @@ var Runeword = { Wealth: [629, 627, 612], // Lem + Ko + Tir White: [623, 625], // Dol + Io Zephyr: [618, 614], // Ort + Eth + // 1.10 Beast: [639, 612, 631, 632, 626], // Ber + Tir + Um + Mal + Lum Bramble: [617, 636, 638, 614], // Ral + Ohm + Sur + Eth @@ -55,29 +58,32 @@ var Runeword = { Splendor: [614, 626], // Eth + Lum Stone: [622, 631, 630, 626], // Shael + Um + Pul + Lum Wind: [638, 610], // Sur + El - Brand: [640, 637, 632, 634], // Jah + Lo + Mal + Gul - Death: [624, 610, 635, 618, 634], // Hel + El + Vex + Ort + Gul - Destruction: [635, 637, 639, 640, 627], // Vex + Lo + Ber + Jah + Ko - Dragon: [638, 637, 621], // Sur + Lo + Sol - Dream: [625, 640, 630], // Io + Jah + Pul - Edge: [612, 616, 620], // Tir + Tal + Amn - Faith: [636, 640, 629, 611], // Ohm + Jah + Lem + Eld - Fortitude: [610, 621, 623, 637], // El + Sol + Dol + Lo - Grief: [614, 612, 637, 632, 617], // Eth + Tir + Lo + Mal + Ral - Harmony: [612, 615, 621, 627], // Tir + Ith + Sol + Ko - Ice: [620, 622, 640, 637], // Amn + Shael + Jah + Lo - "Infinity": [639, 632, 639, 633], // Ber + Mal + Ber + Ist - Insight: [617, 612, 616, 621], // Ral + Tir + Tal + Sol - LastWish: [640, 632, 640, 638, 640, 639], // Jah + Mal + Jah + Sur + Jah + Ber - Lawbringer: [620, 629, 627], // Amn + Lem + Ko - Oath: [622, 630, 632, 626], // Shael + Pul + Mal + Lum - Obedience: [624, 627, 619, 614, 628], // Hel + Ko + Thul + Eth + Fal - Phoenix: [635, 635, 637, 640], // Vex + Vex + Lo + Jah - Pride: [641, 638, 625, 637], // Cham + Sur + Io + Lo - Rift: [624, 627, 629, 634], // Hel + Ko + Lem + Gul - Spirit: [616, 619, 618, 620], // Tal + Thul + Ort + Amn - VoiceofReason: [629, 627, 610, 611], // Lem + Ko + El + Eld - Wrath: [630, 626, 639, 632], // Pul + Lum + Ber + Mal + + // Don't use ladder-only on NL + Brand: me.ladder ? [640, 637, 632, 634] : false, // Jah + Lo + Mal + Gul + Death: me.ladder ? [624, 610, 635, 618, 634] : false, // Hel + El + Vex + Ort + Gul + Destruction: me.ladder ? [635, 637, 639, 640, 627] : false, // Vex + Lo + Ber + Jah + Ko + Dragon: me.ladder ? [638, 637, 621] : false, // Sur + Lo + Sol + Dream: me.ladder ? [625, 640, 630] : false, // Io + Jah + Pul + Edge: me.ladder ? [612, 616, 620] : false, // Tir + Tal + Amn + Faith: me.ladder ? [636, 640, 629, 611] : false, // Ohm + Jah + Lem + Eld + Fortitude: me.ladder ? [610, 621, 623, 637] : false, // El + Sol + Dol + Lo + Grief: me.ladder ? [614, 612, 637, 632, 617] : false, // Eth + Tir + Lo + Mal + Ral + Harmony: me.ladder ? [612, 615, 621, 627] : false, // Tir + Ith + Sol + Ko + Ice: me.ladder ? [620, 622, 640, 637] : false, // Amn + Shael + Jah + Lo + "Infinity": me.ladder ? [639, 632, 639, 633] : false, // Ber + Mal + Ber + Ist + Insight: me.ladder ? [617, 612, 616, 621] : false, // Ral + Tir + Tal + Sol + LastWish: me.ladder ? [640, 632, 640, 638, 640, 639] : false, // Jah + Mal + Jah + Sur + Jah + Ber + Lawbringer: me.ladder ? [620, 629, 627] : false, // Amn + Lem + Ko + Oath: me.ladder ? [622, 630, 632, 626] : false, // Shael + Pul + Mal + Lum + Obedience: me.ladder ? [624, 627, 619, 614, 628] : false, // Hel + Ko + Thul + Eth + Fal + Phoenix: me.ladder ? [635, 635, 637, 640] : false, // Vex + Vex + Lo + Jah + Pride: me.ladder ? [641, 638, 625, 637] : false, // Cham + Sur + Io + Lo + Rift: me.ladder ? [624, 627, 629, 634] : false, // Hel + Ko + Lem + Gul + Spirit: me.ladder ? [616, 619, 618, 620] : false, // Tal + Thul + Ort + Amn + VoiceofReason: me.ladder ? [629, 627, 610, 611] : false, // Lem + Ko + El + Eld + Wrath: me.ladder ? [630, 626, 639, 632] : false, // Pul + Lum + Ber + Mal + // 1.11 Bone: [621, 631, 631], // Sol + Um + Um Enlightenment: [630, 617, 621], // Pul + Ral + Sol @@ -100,25 +106,36 @@ var Runewords = { return; } - var i; + var i, info, parsedLine; this.pickitEntries = []; // initiate pickit entries for (i = 0; i < Config.KeepRunewords.length; i += 1) { - this.pickitEntries.push(NTIP.ParseLineInt(Config.KeepRunewords[i])); + info = { + file: "Character Config", + line: Config.KeepRunewords[i] + }; + + parsedLine = NTIP.ParseLineInt(Config.KeepRunewords[i], info); + + if (parsedLine) { + this.pickitEntries.push(NTIP.ParseLineInt(Config.KeepRunewords[i], info)); + } } // change text to classid for (i = 0; i < Config.Runewords.length; i += 1) { - if (isNaN(Config.Runewords[i][1])) { - if (NTIPAliasClassID.hasOwnProperty(Config.Runewords[i][1].replace(/\s+/g, "").toLowerCase())) { - Config.Runewords[i][1] = NTIPAliasClassID[Config.Runewords[i][1].replace(/\s+/g, "").toLowerCase()]; - } else { - Misc.errorReport("ÿc1Invalid runewords entry:ÿc0 " + Config.Runewords[i][1]); - Config.Runewords.splice(i, 1); - - i -= 1; + if (Config.Runewords[i][0] !== false) { + if (isNaN(Config.Runewords[i][1])) { + if (NTIPAliasClassID.hasOwnProperty(Config.Runewords[i][1].replace(/\s+/g, "").toLowerCase())) { + Config.Runewords[i][1] = NTIPAliasClassID[Config.Runewords[i][1].replace(/\s+/g, "").toLowerCase()]; + } else { + Misc.errorReport("ÿc1Invalid runewords entry:ÿc0 " + Config.Runewords[i][1]); + Config.Runewords.splice(i, 1); + + i -= 1; + } } } } @@ -127,6 +144,10 @@ var Runewords = { }, validItem: function (item) { + if (CraftingSystem.validGids.indexOf(item.gid) > -1) { + return false; + } + return true; }, diff --git a/d2bs/kolbot/libs/common/Storage.js b/d2bs/kolbot/libs/common/Storage.js index ea8a9692d..46ace8303 100644 --- a/d2bs/kolbot/libs/common/Storage.js +++ b/d2bs/kolbot/libs/common/Storage.js @@ -179,7 +179,7 @@ Loop: nDelay = getTickCount(); - while ((getTickCount() - nDelay) < 500) { + while ((getTickCount() - nDelay) < Math.max(1000, me.ping * 3 + 500)) { if (!me.itemoncursor) { print("Successfully placed " + item.name + " at X: " + nPos.x + " Y: " + nPos.y); delay(200); @@ -331,6 +331,7 @@ var Storage = new function () { this.Stash.Reset(); this.Belt.Reset(); this.Cube.Reset(); + this.TradeScreen.Reset(); var item = me.getItem(); @@ -343,6 +344,10 @@ var Storage = new function () { case 3: this.Inventory.Mark(item); + break; + case 5: + this.TradeScreen.Mark(item); + break; case 2: this.Belt.Mark(item); diff --git a/d2bs/kolbot/libs/common/Town.js b/d2bs/kolbot/libs/common/Town.js index f9bc39b62..8aa657b9f 100644 --- a/d2bs/kolbot/libs/common/Town.js +++ b/d2bs/kolbot/libs/common/Town.js @@ -34,8 +34,8 @@ var NPC = { }; var Town = { + telekinesis: true, sellTimer: getTickCount(), // shop speedup test - beltSize: false, tasks: [ {Heal: NPC.Akara, Shop: NPC.Akara, Gamble: NPC.Gheed, Repair: NPC.Charsi, Merc: NPC.Kashya, Key: NPC.Akara, CainID: NPC.Cain}, @@ -67,7 +67,7 @@ var Town = { } var i, - cancelFlags = [0x01, 0x02, 0x04, 0x08, 0x14, 0x16, 0x0c, 0x0f]; + cancelFlags = [0x01, 0x02, 0x04, 0x08, 0x14, 0x16, 0x0c, 0x0f, 0x19, 0x1a]; if (me.classid === 4 && Config.FindItem && Config.FindItemSwitch) { // weapon switch fix in case last game dropped with item find switch on Precast.weaponSwitch(Math.abs(Config.FindItemSwitch - 1)); @@ -77,7 +77,13 @@ var Town = { Precast.weaponSwitch(Math.abs(Config.MFSwitch - 1)); } + if (Precast.haveCTA > -1) { + Precast.weaponSwitch(Math.abs(Precast.haveCTA - 1)); + } + this.heal(); + this.identify(); + this.shopItems(); this.fillTome(518); if (Config.FieldID) { @@ -85,17 +91,14 @@ var Town = { } this.buyPotions(); - this.identify(); - this.shopItems(); + this.clearInventory(); + Item.autoEquip(); this.buyKeys(); this.repair(); this.gamble(); this.reviveMerc(); Cubing.doCubing(); Runewords.makeRunewords(); - - this.clearInventory(); - this.stash(true); this.clearScrolls(); @@ -113,8 +116,51 @@ var Town = { return true; }, + checkQuestItems: function () { + var i, npc, item; + + // golden bird stuff + if (me.getItem(546)) { + this.goToTown(3); + this.move("meshif"); + + npc = getUnit(1, "meshif"); + + if (npc) { + npc.openMenu(); + me.cancel(); + } + } + + if (me.getItem(547)) { + this.goToTown(3); + this.move("alkor"); + + npc = getUnit(1, "alkor"); + + if (npc) { + for (i = 0; i < 2; i += 1) { + npc.openMenu(); + me.cancel(); + } + } + } + + if (me.getItem(545)) { + item = me.getItem(545); + + if (item.location > 3) { + this.openStash(); + } + + item.interact(); + } + }, + // Start a task and return the NPC Unit - initNPC: function (task) { + initNPC: function (task, reason) { + print("initNPC: " + reason); + var npc = getInteractedNPC(); if (npc && npc.name.toLowerCase() !== this.tasks[me.act - 1][task]) { @@ -140,7 +186,7 @@ var Town = { } } - if (!npc || (!getUIFlag(0x08) && !npc.openMenu())) { + if (!npc || npc.area !== me.area || (!getUIFlag(0x08) && !npc.openMenu())) { return false; } @@ -175,7 +221,7 @@ var Town = { return true; } - if (!this.initNPC("Heal")) { + if (!this.initNPC("Heal", "heal")) { return false; } @@ -197,32 +243,77 @@ var Town = { }, buyPotions: function () { - var i, j, npc, useShift, col, beltSize, pot; - - if (!this.beltSize) { - this.beltSize = Storage.BeltSize(); + if (me.gold < 1000) { // Ain't got money fo' dat shyt + return false; } - beltSize = this.beltSize; + var i, j, npc, useShift, col, beltSize, pot, + needPots = false, + needBuffer = true, + buffer = { + hp: 0, + mp: 0 + }; + + beltSize = Storage.BeltSize(); col = this.checkColumns(beltSize); + // HP/MP Buffer + if (Config.HPBuffer > 0 || Config.MPBuffer > 0) { + pot = me.getItem(-1, 0); + + if (pot) { + do { + if (pot.location === 3) { + switch (pot.itemType) { + case 76: + buffer.hp += 1; + + break; + case 77: + buffer.mp += 1; + + break; + } + } + } while (pot.getNext()); + } + } + // Check if we need to buy potions based on Config.MinColumn for (i = 0; i < 4; i += 1) { if (["hp", "mp"].indexOf(Config.BeltColumn[i]) > -1 && col[i] > (beltSize - Math.min(Config.MinColumn[i], beltSize))) { - break; + needPots = true; + } + } + + // Check if we need any potions for buffers + if (buffer.mp < Config.MPBuffer || buffer.hp < Config.HPBuffer) { + for (i = 0; i < 4; i += 1) { + // We can't buy potions because they would go into belt instead + if (col[i] >= beltSize && (!needPots || Config.BeltColumn[i] === "rv")) { + needBuffer = false; + + break; + } } } + // We have enough potions in inventory + if (buffer.mp >= Config.MPBuffer && buffer.hp >= Config.HPBuffer) { + needBuffer = false; + } + // No columns to fill - if (i === 4) { + if (!needPots && !needBuffer) { return true; } if (me.diff === 0 && Pather.accessToAct(4) && me.act < 4) { - Town.goToTown(4); + this.goToTown(4); } - npc = this.initNPC("Shop"); + npc = this.initNPC("Shop", "buyPotions"); if (!npc) { return false; @@ -250,6 +341,26 @@ var Town = { col = this.checkColumns(beltSize); // Re-initialize columns (needed because 1 shift-buy can fill multiple columns) } + if (needBuffer && buffer.hp < Config.HPBuffer) { + for (i = 0; i < Config.HPBuffer - buffer.hp; i += 1) { + pot = this.getPotion(npc, "hp"); + + if (Storage.Inventory.CanFit(pot)) { + pot.buy(false); + } + } + } + + if (needBuffer && buffer.mp < Config.MPBuffer) { + for (i = 0; i < Config.MPBuffer - buffer.mp; i += 1) { + pot = this.getPotion(npc, "mp"); + + if (Storage.Inventory.CanFit(pot)) { + pot.buy(false); + } + } + } + return true; }, @@ -334,12 +445,16 @@ var Town = { }, fillTome: function (code) { + if (me.gold < 450) { + return false; + } + if (this.checkScrolls(code) >= 13) { return true; } var scroll, tome, - npc = this.initNPC("Shop"); + npc = this.initNPC("Shop", "fillTome"); if (!npc) { return false; @@ -347,15 +462,20 @@ var Town = { delay(500); - if (!me.findItem(518, 0, 3)) { + if (code === 518 && !me.findItem(518, 0, 3)) { tome = npc.getItem(518); - if (tome) { + if (tome && Storage.Inventory.CanFit(tome)) { try { tome.buy(); } catch (e1) { print(e1); + + // Couldn't buy the tome, don't spam the scrolls + return false; } + } else { + return false; } } @@ -382,8 +502,10 @@ var Town = { if (!tome) { switch (id) { case 519: + case "ibk": return 20; // Ignore missing ID tome case 518: + case "tbk": return 0; // Force TP tome check } } @@ -406,7 +528,7 @@ var Town = { // Avoid unnecessary NPC visits for (i = 0; i < list.length; i += 1) { // Only unid items or sellable junk (low level) should trigger a NPC visit - if ((!list[i].getFlag(0x10) || Config.LowGold > 0) && [-1, 4].indexOf(Pickit.checkItem(list[i]).result) > -1) { + if ((!list[i].getFlag(0x10) || Config.LowGold > 0) && ([-1, 4].indexOf(Pickit.checkItem(list[i]).result) > -1 || (!list[i].getFlag(0x10) && Item.hasTier(list[i])))) { break; } } @@ -415,7 +537,7 @@ var Town = { return false; } - npc = this.initNPC("Shop"); + npc = this.initNPC("Shop", "identify"); if (!npc) { return false; @@ -434,6 +556,11 @@ MainLoop: if (!item.getFlag(0x10) && item.location === 3 && this.ignoredItemTypes.indexOf(item.itemType) === -1) { result = Pickit.checkItem(item); + // Force ID for unid items matching autoEquip criteria + if (result.result === 1 && !item.getFlag(0x10) && Item.hasTier(item)) { + result.result = -1; + } + switch (result.result) { // Items for gold, will sell magics, etc. w/o id, but at low levels // magics are often not worth iding. @@ -461,7 +588,10 @@ MainLoop: } delay(500); - scroll.buy(); + + if (Storage.Inventory.CanFit(scroll)) { + scroll.buy(); + } } scroll = me.findItem(530, 0, 3); @@ -475,8 +605,17 @@ MainLoop: result = Pickit.checkItem(item); + if (!Item.autoEquipCheck(item)) { + result.result = 0; + } + switch (result.result) { case 1: + // Couldn't id autoEquip item. Don't log it. + if (result.result === 1 && Config.AutoEquip && !item.getFlag(0x10) && Item.autoEquipCheck(item)) { + break; + } + Misc.itemLogger("Kept", item); Misc.logItem("Kept", item, result.line); @@ -489,6 +628,11 @@ MainLoop: break; case 3: // runeword (doesn't trigger normally) + break; + case 5: // Crafting System + Misc.itemLogger("Kept", item, "CraftSys-Town"); + CraftingSystem.update(item); + break; default: Misc.itemLogger("Sold", item); @@ -527,7 +671,7 @@ MainLoop: } // Check if we may use Cain - minimum gold - if (me.getStat(14) + me.getStat(15) < Config.CainID.MinGold) { + if (me.gold < Config.CainID.MinGold) { //print("Can't use Cain - not enough gold."); return false; @@ -555,7 +699,7 @@ MainLoop: } } - cain = this.initNPC("CainID"); + cain = this.initNPC("CainID", "cainID"); if (!cain) { return false; @@ -564,6 +708,10 @@ MainLoop: for (i = 0; i < unids.length; i += 1) { result = Pickit.checkItem(unids[i]); + if (!Item.autoEquipCheck(unids[i])) { + result = 0; + } + switch (result.result) { case 0: Misc.itemLogger("Dropped", unids[i], "cainID"); @@ -603,15 +751,33 @@ MainLoop: item = list.shift(); result = Pickit.checkItem(item); + // Force ID for unid items matching autoEquip criteria + if (result.result === 1 && !item.getFlag(0x10) && Item.hasTier(item)) { + result.result = -1; + } + if (result.result === -1) { // unid item that should be identified this.identifyItem(item, tome); delay(me.ping + 1); result = Pickit.checkItem(item); + if (!Item.autoEquipCheck(item)) { + result.result = 0; + } + switch (result.result) { case 0: Misc.itemLogger("Dropped", item, "fieldID"); + + if (Config.DroppedItemsAnnounce.Enable && Config.DroppedItemsAnnounce.Quality.indexOf(item.quality) > -1) { + say("Dropped: [" + Pickit.itemQualityToName(item.quality).charAt(0).toUpperCase() + Pickit.itemQualityToName(item.quality).slice(1) + "] " + item.fname.split("\n").reverse().join(" ").replace(/ÿc[0-9!"+<;.*]/, "").trim()); + + if (Config.DroppedItemsAnnounce.LogToOOG && Config.DroppedItemsAnnounce.OOGQuality.indexOf(item.quality) > -1) { + Misc.logItem("Field Dropped", item, result.line); + } + } + item.drop(); break; @@ -719,7 +885,7 @@ CursorLoop: items = [], npc = getInteractedNPC(); - if (!npc || !getUIFlag(0x0C) || !npc.itemcount) { + if (!npc || !npc.itemcount) { return false; } @@ -740,7 +906,7 @@ CursorLoop: for (i = 0; i < items.length; i += 1) { result = Pickit.checkItem(items[i]); - if (result.result === 1) { + if (result.result === 1 && Item.autoEquipCheck(items[i])) { try { if (Storage.Inventory.CanFit(items[i]) && me.getStat(14) + me.getStat(15) >= items[i].getItemCost(0)) { Misc.itemLogger("Shopped", items[i]); @@ -758,20 +924,41 @@ CursorLoop: return true; }, + gambleIds: [], + gamble: function () { - if (!this.needGamble() || !Config.GambleItems.length) { + if (!this.needGamble() || Config.GambleItems.length === 0) { return true; } var i, item, items, npc, newItem, result, list = []; + if (this.gambleIds.length === 0) { + // change text to classid + for (i = 0; i < Config.GambleItems.length; i += 1) { + if (isNaN(Config.GambleItems[i])) { + if (NTIPAliasClassID.hasOwnProperty(Config.GambleItems[i].replace(/\s+/g, "").toLowerCase())) { + this.gambleIds.push(NTIPAliasClassID[Config.GambleItems[i].replace(/\s+/g, "").toLowerCase()]); + } else { + Misc.errorReport("ÿc1Invalid gamble entry:ÿc0 " + Config.GambleItems[i]); + } + } else { + this.gambleIds.push(Config.GambleItems[i]); + } + } + } + + if (this.gambleIds.length === 0) { + return true; + } + // Fuck Alkor if (me.act === 3) { this.goToTown(2); } - npc = this.initNPC("Gamble"); + npc = this.initNPC("Gamble", "gamble"); if (!npc) { return false; @@ -779,11 +966,11 @@ CursorLoop: items = me.findItems(-1, 0, 3); - while (items.length > 0) { + while (items && items.length > 0) { list.push(items.shift().gid); } - while (me.getStat(14) + me.getStat(15) >= Config.GambleGoldStop) { + while (me.gold >= Config.GambleGoldStop) { if (!getInteractedNPC()) { npc.startTrade("Gamble"); } @@ -793,7 +980,7 @@ CursorLoop: if (item) { do { - if (Config.GambleItems.indexOf(item.classid) > -1) { + if (this.gambleIds.indexOf(item.classid) > -1) { items.push(copyUnit(item)); } } while (item.getNext()); @@ -811,6 +998,10 @@ CursorLoop: if (newItem) { result = Pickit.checkItem(newItem); + if (!Item.autoEquipCheck(newItem)) { + result = 0; + } + switch (result.result) { case 1: Misc.itemLogger("Gambled", newItem); @@ -822,6 +1013,10 @@ CursorLoop: list.push(newItem.gid); Cubing.update(); + break; + case 5: // Crafting System + CraftingSystem.update(newItem); + break; default: Misc.itemLogger("Sold", newItem, "Gambling"); @@ -845,7 +1040,7 @@ CursorLoop: }, needGamble: function () { - return Config.Gamble && me.getStat(14) + me.getStat(15) >= Config.GambleGoldStart; + return Config.Gamble && me.gold >= Config.GambleGoldStart; }, getGambledItem: function (list) { @@ -880,7 +1075,7 @@ CursorLoop: } var key, - npc = this.initNPC("Key"); + npc = this.initNPC("Key", "buyKeys"); if (!npc) { return false; @@ -904,7 +1099,7 @@ CursorLoop: }, checkKeys: function () { - if (!Config.OpenChests || me.classid === 6) { + if (!Config.OpenChests || me.classid === 6 || me.gold < 540 || (!me.getItem("key") && !Storage.Inventory.CanFit({sizex: 1, sizey: 1}))) { return 12; } @@ -985,8 +1180,7 @@ CursorLoop: return false; } - var i, - items = this.getItemsForRepair(Config.RepairPercent, false); + var items = this.getItemsForRepair(Config.RepairPercent, false); items.sort(function (a, b) { return a.getStat(72) * 100 / a.getStat(73) - b.getStat(72) * 100 / b.getStat(73); @@ -1077,15 +1271,15 @@ CursorLoop: return true; } - npc = this.initNPC("Repair"); - - if (!npc) { - return false; - } - for (i = 0; i < repairAction.length; i += 1) { switch (repairAction[i]) { case "repair": + npc = this.initNPC("Repair", "repair"); + + if (!npc) { + return false; + } + me.repair(); break; @@ -1093,16 +1287,27 @@ CursorLoop: bowCheck = Attack.usingBow(); if (bowCheck) { - quiver = bowCheck === "bow" ? npc.getItem("aqv") : quiver = npc.getItem("cqv"); + if (bowCheck === "bow") { + quiver = "aqv"; // Arrows + } else { + quiver = "cqv"; // Bolts + } - if (quiver) { - myQuiver = me.getItem(quiver.code, 1); + myQuiver = me.getItem(quiver, 1); - if (myQuiver) { - myQuiver.sell(); - delay(500); - } + if (myQuiver) { + myQuiver.drop(); + } + + npc = this.initNPC("Repair", "repair"); + + if (!npc) { + return false; + } + + quiver = npc.getItem(quiver); + if (quiver) { quiver.buy(); } } @@ -1119,7 +1324,7 @@ CursorLoop: needRepair: function () { var quiver, bowCheck, quantity, repairAction = [], - canAfford = me.getStat(14) + me.getStat(15) >= me.getRepairCost(); + canAfford = me.gold >= me.getRepairCost(); // Arrow/Bolt check bowCheck = Attack.usingBow(); @@ -1219,8 +1424,14 @@ CursorLoop: return true; } + // Fuck Aheara + if (me.act === 3) { + this.goToTown(2); + } + var i, tick, dialog, lines, - npc = this.initNPC("Merc"); + preArea = me.area, + npc = this.initNPC("Merc", "reviveMerc"); if (!npc) { return false; @@ -1243,7 +1454,7 @@ MainLoop: } while (getTickCount() - tick < 2000) { - if (me.getMerc()) { + if (!!me.getMerc()) { delay(Math.max(750, me.ping * 2)); break MainLoop; @@ -1255,13 +1466,24 @@ MainLoop: Attack.checkInfinity(); - return !!me.getMerc(); + if (!!me.getMerc()) { + if (Config.MercWatch) { // Cast BO on merc so he doesn't just die again + print("MercWatch precast"); + Pather.useWaypoint("random"); + Precast.doPrecast(true); + Pather.useWaypoint(preArea); + } + + return true; + } + + return false; }, needMerc: function () { var i, merc; - if (me.gametype === 0 || !Config.UseMerc || me.getStat(14) + me.getStat(15) < me.mercrevivecost) { // gametype 0 = classic + if (me.gametype === 0 || !Config.UseMerc || me.gold < me.mercrevivecost) { // gametype 0 = classic return false; } @@ -1283,6 +1505,16 @@ MainLoop: return true; }, + canStash: function (item) { + var ignoredClassids = [91, 174]; // Some quest items that have to be in inventory or equipped + + if (this.ignoredItemTypes.indexOf(item.itemType) > -1 || ignoredClassids.indexOf(item.classid) > -1 || !Storage.Stash.CanFit(item)) { + return false; + } + + return true; + }, + stash: function (stashGold) { if (stashGold === undefined) { stashGold = true; @@ -1294,13 +1526,22 @@ MainLoop: me.cancel(); - var i, result, + var i, result, tier, items = Storage.Inventory.Compare(Config.Inventory); if (items) { for (i = 0; i < items.length; i += 1) { - if (this.ignoredItemTypes.indexOf(items[i].itemType) === -1 && Storage.Stash.CanFit(items[i])) { - result = (Pickit.checkItem(items[i]).result > 0 && Pickit.checkItem(items[i]).result < 4) || Cubing.keepItem(items[i]) || Runewords.keepItem(items[i]); + if (this.canStash(items[i])) { + result = (Pickit.checkItem(items[i]).result > 0 && Pickit.checkItem(items[i]).result < 4) || Cubing.keepItem(items[i]) || Runewords.keepItem(items[i]) || CraftingSystem.keepItem(items[i]); + + // Don't stash low tier autoequip items. + if (Config.AutoEquip && Pickit.checkItem(items[i]).result === 1) { + tier = NTIP.GetTier(items[i]); + + if (tier > 0 && tier < 100) { + result = false; + } + } if (result) { Misc.itemLogger("Stashed", items[i]); @@ -1345,7 +1586,7 @@ MainLoop: } var i, tick, stash, - useTK = me.classid === 1 && me.getSkill(43, 1); + telekinesis = me.classid === 1 && me.getSkill(43, 1); for (i = 0; i < 5; i += 1) { this.move("stash"); @@ -1353,7 +1594,7 @@ MainLoop: stash = getUnit(2, 267); if (stash) { - if (useTK) { + if (telekinesis) { Skill.cast(43, 0, stash); } else { Misc.click(0, 0, stash); @@ -1382,7 +1623,7 @@ MainLoop: this.move("stash"); } - useTK = false; + telekinesis = false; } } @@ -1390,18 +1631,31 @@ MainLoop: }, getCorpse: function () { - var corpse, gid, + var i, corpse, gid, corpseList = [], timer = getTickCount(); - corpse = getUnit(0, me.name, 17); + // No equipped items - high chance of dying in last game, force retries + if (!me.getItem(-1, 1)) { + for (i = 0; i < 5; i += 1) { + corpse = getUnit(0, me.name, 17); + + if (corpse) { + break; + } + + delay(500); + } + } else { + corpse = getUnit(0, me.name, 17); + } if (!corpse) { return true; } do { - if (getDistance(me.x, me.y, corpse.x, corpse.y) <= 20) { + if (corpse.dead && corpse.name === me.name && (getDistance(me.x, me.y, corpse.x, corpse.y) <= 20 || me.inTown)) { corpseList.push(copyUnit(corpse)); } } while (corpse.getNext()); @@ -1537,8 +1791,14 @@ MainLoop: for (i = 0; !!items && i < items.length; i += 1) { if (items[i].location === 3 && items[i].mode === 0 && items[i].itemType === 22) { - Misc.itemLogger("Dropped", items[i], "clearScrolls"); - items[i].drop(); + if (getUIFlag(0xC) || (Config.PacketShopping && getInteractedNPC() && getInteractedNPC().itemcount > 0)) { // Might as well sell the item if already in shop + print("clearInventory sell " + items[i].name); + Misc.itemLogger("Sold", items[i]); + items[i].sell(); + } else { + Misc.itemLogger("Dropped", items[i], "clearScrolls"); + items[i].drop(); + } } } @@ -1546,13 +1806,14 @@ MainLoop: }, clearInventory: function () { - var i, loseItemAction, col, - dropAction = 0, - sellAction = 1, - item = me.getItem(-1, 0), + var i, col, result, item, beltSize, items = []; - // Handle potions + this.checkQuestItems(); // only golden bird quest for now + + // Return potions to belt + item = me.getItem(-1, 0); + if (item) { do { if (item.location === 3 && [76, 77, 78].indexOf(item.itemType) > -1) { @@ -1560,11 +1821,8 @@ MainLoop: } } while (item.getNext()); - if (!this.beltSize) { - this.beltSize = Storage.BeltSize(); - } - - col = this.checkColumns(this.beltSize); + beltSize = Storage.BeltSize(); + col = this.checkColumns(beltSize); // Sort from HP to RV items.sort(function (a, b) { @@ -1574,107 +1832,121 @@ MainLoop: while (items.length) { item = items.shift(); -MainSwitch: - // Redundant but will do for now - switch (item.itemType) { - case 76: - for (i = 0; i < 4; i += 1) { - if (Config.BeltColumn[i] === "hp" && col[i] > 0) { - clickItem(2, item.x, item.y, item.location); // Return potion to belt - delay(me.ping + 200); - - col = this.checkColumns(this.beltSize); - - break MainSwitch; + for (i = 0; i < 4; i += 1) { + if (item.code.indexOf(Config.BeltColumn[i]) > -1 && col[i] > 0) { + if (col[i] === beltSize) { // Pick up the potion and put it in belt if the column is empty + if (item.toCursor()) { + clickItem(0, i, 0, 2); + } + } else { + clickItem(2, item.x, item.y, item.location); // Shift-click potion } - } - if (!Config.HPBuffer) { - item.interact(); delay(me.ping + 200); - } - break; - case 77: - for (i = 0; i < 4; i += 1) { - if (Config.BeltColumn[i] === "mp" && col[i] > 0) { - clickItem(2, item.x, item.y, item.location); - delay(me.ping + 200); - - col = this.checkColumns(this.beltSize); - - break MainSwitch; - } + col = this.checkColumns(beltSize); } + } + } + } - if (!Config.MPBuffer) { - item.interact(); - delay(me.ping + 200); - } + // Cleanup remaining potions + item = me.getItem(-1, 0); - break; - case 78: - for (i = 0; i < 4; i += 1) { - if (Config.BeltColumn[i] === "rv" && col[i] > 0) { - clickItem(2, item.x, item.y, item.location); - delay(me.ping + 200); + if (item) { + items = [ + [], // array for hp + [] // array for mp + ]; - col = this.checkColumns(this.beltSize); + do { + if (item.itemType === 76) { + items[0].push(copyUnit(item)); + } - break MainSwitch; - } - } + if (item.itemType === 77) { + items[1].push(copyUnit(item)); + } + } while (item.getNext()); - if (!Config.RejuvBuffer) { - item.interact(); - delay(me.ping + 200); - } + // Cleanup healing potions + while (items[0].length > Config.HPBuffer) { + items[0].shift().interact(); + delay(200 + me.ping); + } - break; - } + // Cleanup mana potions + while (items[1].length > Config.MPBuffer) { + items[1].shift().interact(); + delay(200 + me.ping); } } // Any leftover items from a failed ID (crashed game, disconnect etc.) items = Storage.Inventory.Compare(Config.Inventory); - // If low on gold - if (me.getStat(14) + me.getStat(15) < Config.LowGold) { - this.initNPC("Shop"); - - loseItemAction = sellAction; - } else { - loseItemAction = dropAction; - } - for (i = 0; !!items && i < items.length; i += 1) { - if ([18, 41, 78].indexOf(items[i].itemType) === -1 && - items[i].classid !== 549 && - (items[i].code !== 529 || !!me.findItem(518, 0, 3)) && - (items[i].code !== 530 || !!me.findItem(519, 0, 3)) && - (Pickit.checkItem(items[i]).result === 0 || Pickit.checkItem(items[i]).result === 4) && - !Cubing.keepItem(items[i]) && - !Runewords.keepItem(items[i]) + if ([18, 41, 76, 77, 78].indexOf(items[i].itemType) === -1 && // Don't drop tomes, keys or potions + // Keep some quest items + items[i].classid !== 524 && // Scroll of Inifuss + items[i].classid !== 525 && // Key to Cairn Stones + items[i].classid !== 549 && // Horadric Cube + items[i].classid !== 92 && // Staff of Kings + items[i].classid !== 521 && // Viper Amulet + items[i].classid !== 91 && // Horadric Staff + items[i].classid !== 552 && // Book of Skill + items[i].classid !== 545 && // Potion of Life + items[i].classid !== 546 && // A Jade Figurine + items[i].classid !== 547 && // The Golden Bird + items[i].classid !== 548 && // Lam Esen's Tome + items[i].classid !== 553 && // Khalim's Eye + items[i].classid !== 554 && // Khalim's Heart + items[i].classid !== 555 && // Khalim's Brain + items[i].classid !== 173 && // Khalim's Flail + items[i].classid !== 174 && // Khalim's Will + items[i].classid !== 644 && // Malah's Potion + items[i].classid !== 646 && // Scroll of Resistance + // + (items[i].code !== 529 || !!me.findItem(518, 0, 3)) && // Don't throw scrolls if no tome is found (obsolete code?) + (items[i].code !== 530 || !!me.findItem(519, 0, 3)) && // Don't throw scrolls if no tome is found (obsolete code?) + !Cubing.keepItem(items[i]) && // Don't throw cubing ingredients + !Runewords.keepItem(items[i]) && // Don't throw runeword ingredients + !CraftingSystem.keepItem(items[i]) // Don't throw crafting system ingredients ) { - try { - if (loseItemAction === sellAction) { + result = Pickit.checkItem(items[i]).result; + + if (!Item.autoEquipCheck(items[i])) { + result = 0; + } + + switch (result) { + case 0: // Drop item + if ((getUIFlag(0x0C) || getUIFlag(0x08)) && (items[i].getItemCost(1) <= 1 || items[i].itemType === 39)) { // Quest items and such + me.cancel(); + delay(200); + } + + if (getUIFlag(0xC) || (Config.PacketShopping && getInteractedNPC() && getInteractedNPC().itemcount > 0)) { // Might as well sell the item if already in shop + print("clearInventory sell " + items[i].name); Misc.itemLogger("Sold", items[i]); items[i].sell(); } else { Misc.itemLogger("Dropped", items[i], "clearInventory"); - - // TEMP - /*if (items[i].name.match("flawless", "i")) { - D2Bot.printToConsole("QQ", 9); - D2Bot.stop(); - - return true; - }*/ - items[i].drop(); } - } catch (e) { - print(e); + + break; + case 4: // Sell item + try { + print("LowGold sell " + items[i].name); + this.initNPC("Shop", "clearInventory"); + Misc.itemLogger("Sold", items[i]); + items[i].sell(); + } catch (e) { + print(e); + } + + break; } } } @@ -1723,10 +1995,10 @@ MainSwitch: this.act[1].spot.sewers = [5221, 5181]; this.act[1].spot.meshif = [5205, 5058]; this.act[1].spot[NPC.Drognan] = [5097, 5035]; - this.act[1].spot.atma = [5140, 5055]; + this.act[1].spot.atma = [5137, 5060]; this.act[1].spot.warriv = [5152, 5201]; - this.act[1].spot.portalspot = [5168, 5055]; - this.act[1].spot.stash = [5124, 5082]; + this.act[1].spot.portalspot = [5168, 5060]; + this.act[1].spot.stash = [5124, 5076]; this.act[1].spot.waypoint = [5070, 5083]; this.act[1].initialized = true; @@ -1779,23 +2051,15 @@ MainSwitch: move: function (spot) { if (!me.inTown) { - throw new Error("move: Not in town"); + this.goToTown(); } - var i, townSpot, path, - rval = false, - useTK = me.classid === 1 && ((me.getSkill(43, 1) && ["stash", "portalspot"].indexOf(spot) > -1) || spot === "waypoint"); + var i, path; if (!this.act[me.act - 1].initialized) { this.initialize(); } - if (typeof (this.act[me.act - 1].spot[spot]) === "object") { - townSpot = this.act[me.act - 1].spot[spot]; - } else { - return false; - } - // Act 5 wp->portalspot override - ActMap.cpp crash if (me.act === 5 && spot === "portalspot" && getDistance(me.x, me.y, 5113, 5068) <= 8) { path = [5113, 5068, 5108, 5051, 5106, 5046, 5104, 5041, 5102, 5027, 5098, 5018]; @@ -1807,42 +2071,91 @@ MainSwitch: return true; } - if (useTK) { - path = getPath(me.area, townSpot[0], townSpot[1], me.x, me.y, 1, 11); + for (i = 0; i < 3; i += 1) { + if (this.moveToSpot(spot)) { + return true; + } + + Packet.flash(me.gid); + } + + return false; + }, + + moveToSpot: function (spot) { + var i, path, townSpot, + longRange = (me.classid === 1 && this.telekinesis && me.getSkill(43, 1) && ["stash", "portalspot"].indexOf(spot) > -1) || spot === "waypoint"; + + if (!this.act[me.act - 1].hasOwnProperty("spot") || !this.act[me.act - 1].spot.hasOwnProperty(spot)) { + return false; + } + + if (typeof (this.act[me.act - 1].spot[spot]) === "object") { + townSpot = this.act[me.act - 1].spot[spot]; + } else { + return false; + } + + if (longRange) { + path = getPath(me.area, townSpot[0], townSpot[1], me.x, me.y, 1, 8); if (path && path[1]) { - rval = Pather.moveTo(path[1].x, path[1].y); + townSpot = [path[1].x, path[1].y]; } - } else { - print("Townmove: " + spot + " from " + me.x + ", " + me.y); - delay(100); + } - for (i = 0; i < 3; i += 1) { - rval = Pather.moveTo(townSpot[0], townSpot[1]); + for (i = 0; i < townSpot.length; i += 2) { + //print("moveToSpot: " + spot + " from " + me.x + ", " + me.y); - // If unit has more than one location and it's not here, search - if (townSpot.length > 2 && !getUnit(1, spot)) { - for (i = 0; i < townSpot.length / 2; i += 1) { - rval = Pather.moveTo(townSpot[i * 2], townSpot[i * 2 + 1]); + if (getDistance(me, townSpot[i], townSpot[i + 1]) > 2) { + Pather.moveTo(townSpot[i], townSpot[i + 1], 3, false, true); + } - if (!!getUnit(1, spot)) { - break; - } - } + switch (spot) { + case "stash": + if (!!getUnit(2, 267)) { + return true; } - if (rval) { - break; + break; + case "cain": + if (!!getUnit(1, NPC.Cain)) { + return true; } - Packet.flash(me.gid); + break; + case "palace": + if (!!getUnit(1, "jerhyn")) { + return true; + } + + break; + case "portalspot": + case "sewers": + if (getDistance(me, townSpot[i], townSpot[i + 1]) < 10) { + return true; + } + + break; + case "waypoint": + if (!!getUnit(2, "waypoint")) { + return true; + } + + break; + default: + if (!!getUnit(1, spot)) { + return true; + } + + break; } } - return rval; + return false; }, - goToTown: function (act) { + goToTown: function (act, wpmenu) { var towns = [1, 40, 75, 103, 109]; if (!me.inTown) { @@ -1863,8 +2176,12 @@ MainSwitch: throw new Error("Town.goToTown: Invalid act"); } - if (act !== me.act && !Pather.useWaypoint(towns[act - 1])) { - throw new Error("Town.goToTown: Failed to go to town"); + if (act !== me.act) { + try { + Pather.useWaypoint(towns[act - 1], wpmenu); + } catch (WPError) { + throw new Error("Town.goToTown: Failed use WP"); + } } return true; diff --git a/d2bs/kolbot/libs/config/Amazon.js b/d2bs/kolbot/libs/config/Amazon.js index 7a977c92b..9b8b0a28e 100644 --- a/d2bs/kolbot/libs/config/Amazon.js +++ b/d2bs/kolbot/libs/config/Amazon.js @@ -86,6 +86,7 @@ function LoadConfig() { Config.Diablo.EntranceTP = "Entrance TP up"; Config.Diablo.StarTP = "Star TP up"; Config.Diablo.DiabloMsg = "Diablo"; + Scripts.SealLeader = false; // Clear a safe spot around seals and invite leechers in. Leechers should run SealLeecher script. Don't run with Diablo or FastDiablo. // *** act 5 *** Scripts.Pindleskin = false; @@ -124,15 +125,19 @@ function LoadConfig() { Config.Leader = ""; // Leader's ingame character name. Leave blank to try auto-detection (works in AutoBaal, Wakka, MFHelper) Config.QuitList = [""]; // List of character names to quit with. Example: Config.QuitList = ["MySorc", "MyDin"]; + Config.QuitListMode = 0; // 0 = use character names; 1 = use profile names (all profiles must run on the same computer). Scripts.TristramLeech = false; // Enters Tristram, attempts to stay close to the leader and will try and help kill. Scripts.TravincalLeech = false; // Enters portal at back of Travincal. Config.TravincalLeech.Helper = true; // If set to true the character will teleport to the stairs and help attack. Scripts.MFHelper = false; // Run the same MF run as the MFLeader. Leader must have Config.MFLeader = true - Scripts.Wakka = false; // Walking chaos leecher with auto leader assignment, stays at safe distance from the leeader + Scripts.Wakka = false; // Walking chaos leecher with auto leader assignment, stays at safe distance from the leader + Scripts.SealLeecher = false; // Enter safe portals to Chaos. Leader should run SealLeader. Scripts.DiabloHelper = false; // Chaos helper, kills monsters and doesn't open seals on its own. - Config.DiabloHelper.Wait = 120; // Seconds to wait for a runner to be in Chaos - Config.DiabloHelper.Entrance = true; // Start from entrance + Config.DiabloHelper.Wait = 120; // Seconds to wait for a runner to be in Chaos. If Config.Leader is set, it will wait only for the leader. + Config.DiabloHelper.Entrance = true; // Start from entrance. Set to false to start from star. + Config.DiabloHelper.SkipTP = false; // Don't wait for town portal and directly head to chaos. It will clear monsters around chaos entrance and wait for the runner. + Config.DiabloHelper.SkipIfBaal = false; // End script if there are party members in a Baal run. Scripts.AutoBaal = false; // Baal leecher with auto leader assignment Config.AutoBaal.FindShrine = false; // false = disabled, 1 = search after hot tp message, 2 = search as soon as leader is found Config.AutoBaal.LeechSpot = [15115, 5050]; // X, Y coords of Throne Room leech spot @@ -155,14 +160,21 @@ function LoadConfig() { Config.OrgTorch.WaitTimeout = 15; // Time in minutes to wait for keys before moving on Config.OrgTorch.UseSalvation = true; // Use Salvation aura on Mephisto (if possible) Config.OrgTorch.GetFade = false; // Get fade by standing in a fire. You MUST have Last Wish or Treachery on your character being worn. - Scripts.Rusher = false; // Rush bot alpha version (no questing yet, only rushing), for a list of commands, see Rusher.js + Scripts.Rusher = false; // Rush bot. For a list of commands, see Rusher.js Config.Rusher.WaitPlayerCount = 0; // Wait until game has a certain number of players (0 - don't wait, 8 - wait for full game). - Scripts.Rushee = false; // Automatic rushee, works with Rusher + Config.Rusher.Radament = false; // Do Radament quest. + Config.Rusher.LamEsen = false; // Do Lam Esen quest. + Config.Rusher.Izual = false; // Do Izual quest. + Config.Rusher.Shenk = false; // Do Shenk quest. + Config.Rusher.Anya = false; // Do Anya quest. + Config.Rusher.LastRun = ""; // End rush after this run. List of runs: http://pastebin.com/Uez3nZ6g + Scripts.Rushee = false; // Automatic rushee, works with Rusher. Set Rusher's character name as Config.Leader Config.Rushee.Quester = false; // Enter portals and get quest items. Config.Rushee.Bumper = false; // Do Ancients and Baal. Minimum levels: 20 - norm, 40 - nightmare Scripts.CrushTele = false; // classic rush teleporter. go to area of interest and press "-" numpad key Scripts.Questing = false; // solves missing quests (skill/stat+shenk) Scripts.Gamble = false; // Gambling system, other characters will mule gold into your game so you can gamble infinitely. See Gambling.js + Scripts.Crafting = false; // Crafting system, other characters will mule crafting ingredients. See CraftingSystem.js Scripts.GhostBusters = false; // Kill ghosts in most areas that contain them Scripts.Enchant = false; Config.Enchant.Triggers = ["chant", "cows", "wps"]; // Chat commands for enchant, cow level and waypoint giving @@ -173,17 +185,21 @@ function LoadConfig() { Config.IPHunter.IPList = []; // List of IPs to look for. example: [165, 201, 64] Config.IPHunter.GameLength = 3; // Number of minutes to stay in game if ip wasn't found Scripts.KillDclone = false; // Kill Diablo Clone by using Arcane Sanctuary waypoint. Diablo needs to walk the Earth in the game. - Scripts.ShopBot = false; // Fast waypoint-based shopbot - Config.ShopBot.ShopNPC = "Anya"; // Supported NPCs: Fara, Ormus, Anya, Elzix - // Scan only selected classids for maximum speed. See libs/config/templates/ShopBot.txt - Config.ShopBot.ScanIDs = [187, 188, 194, 195, 326, 327, 338, 373, 397, 443, 449]; - Scripts.ChestMania = false; // Open chests in configured areas + Scripts.ShopBot = false; // Shopbot script. Automatically uses shopbot.nip and ignores other pickits. + // Supported NPCs: Akara, Elzix, Fara, Drognan, Ormus, Asheara, Anya. Multiple NPCs are also supported, example: ["Elzix", "Fara"] + // Use common sense when combining NPCs. Shopping in different acts will probably lead to bugs. + Config.ShopBot.ShopNPC = "Anya"; + // Put item classid numbers or names to scan (remember to put quotes around names). Leave blank to scan ALL items. See libs/config/templates/ShopBot.txt + Config.ShopBot.ScanIDs = []; + Config.ShopBot.CycleDelay = 0; // Delay between shopping cycles in milliseconds, might help with crashes. + Config.ShopBot.QuitOnMatch = false; // Leave game as soon as an item is shopped. + Scripts.ChestMania = false; // Open chests in configured areas. See sdk/areas.txt Config.ChestMania.Act1 = [13, 14, 15, 16, 18, 19]; // List of act 1 areas to open chests in Config.ChestMania.Act2 = [55, 59, 65, 66, 67, 68, 69, 70, 71, 72]; // List of act 2 areas to open chests in Config.ChestMania.Act3 = [79, 80, 81, 92, 93, 84, 85, 90]; // List of act 3 areas to open chests in Config.ChestMania.Act4 = []; // List of act 4 areas to open chests in Config.ChestMania.Act5 = [115, 116, 119, 125, 126, 127]; // List of act 5 areas to open chests in - Scripts.ClearAnyArea = false; // Clear any area + Scripts.ClearAnyArea = false; // Clear any area. Uses Config.ClearType to determine which type of monsters to kill. Config.ClearAnyArea.AreaList = []; // List of area ids to clear. See sdk/areas.txt // *** Guest scripts *** @@ -269,13 +285,15 @@ function LoadConfig() { // Additional item info log settings. All info goes to \logs\ItemLog.txt Config.ItemInfo = false; // Log stashed, skipped (due to no space) or sold items. - Config.ItemInfoQuality = []; // The quality of sold items to log. + Config.ItemInfoQuality = []; // The quality of sold items to log. See NTItemAlias.dbl for values. Example: Config.ItemInfoQuality = [6, 7, 8]; // Item identification settings Config.CainID.Enable = false; // Identify items at Cain Config.CainID.MinGold = 2500000; // Minimum gold (stash + character) to have in order to use Cain. Config.CainID.MinUnids = 3; // Minimum number of unid items in order to use Cain. Config.FieldID = false; // Identify items in the field instead of going to town. + Config.DroppedItemsAnnounce.Enable = false; // Announce Dropped Items to in-game newbs + Config.DroppedItemsAnnounce.Quality = []; // Quality of item to announce. See NTItemAlias.dbl for values. Example: Config.DroppedItemsAnnounce.Quality = [6, 7, 8]; // Repair settings Config.CubeRepair = false; // Repair weapons with Ort and armor with Ral rune. Don't use it if you don't understand the risk of losing items. @@ -286,73 +304,73 @@ function LoadConfig() { Config.GambleGoldStart = 1000000; Config.GambleGoldStop = 500000; - // Check libs/NTItemAlias.dbl file for other item classids - Config.GambleItems.push(520); // Amulet - Config.GambleItems.push(522); // Ring - Config.GambleItems.push(418); // Circlet - Config.GambleItems.push(419); // Coronet + // List of item names or classids for gambling. Check libs/NTItemAlias.dbl file for other item classids. + Config.GambleItems.push("Amulet"); + Config.GambleItems.push("Ring"); + Config.GambleItems.push("Circlet"); + Config.GambleItems.push("Coronet"); - /* Cubing config. All recipe names are available in Templates/Cubing.txt - * The format is Config.Recipes.push([recipe_name, item_id, etherealness]). Etherealness is optional and only applies to some recipes. + /* Cubing config. All recipe names are available in Templates/Cubing.txt. For item names/classids check NTItemAlias.dbl + * The format is Config.Recipes.push([recipe_name, item_name_or_classid, etherealness]). Etherealness is optional and only applies to some recipes. */ Config.Cubing = false; // Set to true to enable cubing. // Ingredients for the following recipes will be auto-picked, for classids check libs/NTItemAlias.dbl - //Config.Recipes.push([Recipe.Gem, 560]); // perfect amethyst - //Config.Recipes.push([Recipe.Gem, 565]); // perfect topaz - //Config.Recipes.push([Recipe.Gem, 570]); // perfect sapphire - //Config.Recipes.push([Recipe.Gem, 575]); // perfect emerald - //Config.Recipes.push([Recipe.Gem, 580]); // perfect ruby - //Config.Recipes.push([Recipe.Gem, 585]); // perfect diamond - //Config.Recipes.push([Recipe.Gem, 600]); // perfect skull + //Config.Recipes.push([Recipe.Gem, "Flawless Amethyst"]); // Make Perfect Amethyst + //Config.Recipes.push([Recipe.Gem, "Flawless Topaz"]); // Make Perfect Topaz + //Config.Recipes.push([Recipe.Gem, "Flawless Sapphire"]); // Make Perfect Sapphire + //Config.Recipes.push([Recipe.Gem, "Flawless Emerald"]); // Make Perfect Emerald + //Config.Recipes.push([Recipe.Gem, "Flawless Ruby"]); // Make Perfect Ruby + //Config.Recipes.push([Recipe.Gem, "Flawless Diamond"]); // Make Perfect Diamond + //Config.Recipes.push([Recipe.Gem, "Flawless Skull"]); // Make Perfect Skull - //Config.Recipes.push([Recipe.Token]); // token of absolution - - //Config.Recipes.push([Recipe.Rune, 630]); // pul -> um - //Config.Recipes.push([Recipe.Rune, 631]); // um -> mal - //Config.Recipes.push([Recipe.Rune, 632]); // mal -> ist - //Config.Recipes.push([Recipe.Rune, 633]); // ist -> gul - //Config.Recipes.push([Recipe.Rune, 634]); // gul -> vex + //Config.Recipes.push([Recipe.Token]); // Make Token of Absolution + + //Config.Recipes.push([Recipe.Rune, "Pul Rune"]); // Upgrade Pul to Um + //Config.Recipes.push([Recipe.Rune, "Um Rune"]); // Upgrade Um to Mal + //Config.Recipes.push([Recipe.Rune, "Mal Rune"]); // Upgrade Mal to Ist + //Config.Recipes.push([Recipe.Rune, "Ist Rune"]); // Upgrade Ist to Gul + //Config.Recipes.push([Recipe.Rune, "Gul Rune"]); // Upgrade Gul to Vex //Config.Recipes.push([Recipe.Caster.Amulet]); // Craft Caster Amulet //Config.Recipes.push([Recipe.Blood.Ring]); // Craft Blood Ring - //Config.Recipes.push([Recipe.Blood.Helm, 424]); // Craft Blood Armet - //Config.Recipes.push([Recipe.HitPower.Gloves, 452]); // Craft Hit Power Vambraces + //Config.Recipes.push([Recipe.Blood.Helm, "Armet"]); // Craft Blood Armet + //Config.Recipes.push([Recipe.HitPower.Gloves, "Vambraces"]); // Craft Hit Power Vambraces // The gems not used by other recipes will be used for magic item rerolling. - //Config.Recipes.push([Recipe.Reroll.Magic, 421]); // Reroll magic Diadem - //Config.Recipes.push([Recipe.Reroll.Magic, 605]); // Reroll magic Grand Charm (ilvl 91+) + //Config.Recipes.push([Recipe.Reroll.Magic, "Diadem"]); // Reroll magic Diadem + //Config.Recipes.push([Recipe.Reroll.Magic, "Grand Charm"]); // Reroll magic Grand Charm (ilvl 91+) - //Config.Recipes.push([Recipe.Reroll.Rare, 421]); // Reroll rare Diadem + //Config.Recipes.push([Recipe.Reroll.Rare, "Diadem"]); // Reroll rare Diadem /* Base item for the following recipes must be in pickit. The rest of the ingredients will be auto-picked. * Use Roll.Eth, Roll.NonEth or Roll.All to determine what kind of base item to roll - ethereal, non-ethereal or all. */ - //Config.Recipes.push([Recipe.Socket.Weapon, 255, Roll.Eth]); // Socket ethereal Thresher - //Config.Recipes.push([Recipe.Socket.Weapon, 256, Roll.Eth]); // Socket ethereal Cryptic Axe - //Config.Recipes.push([Recipe.Socket.Armor, 442, Roll.Eth]); // Socket ethereal Sacred Armor - //Config.Recipes.push([Recipe.Socket.Armor, 443, Roll.Eth]); // Socket ethereal Archon Plate + //Config.Recipes.push([Recipe.Socket.Weapon, "Thresher", Roll.Eth]); // Socket ethereal Thresher + //Config.Recipes.push([Recipe.Socket.Weapon, "Cryptic Axe", Roll.Eth]); // Socket ethereal Cryptic Axe + //Config.Recipes.push([Recipe.Socket.Armor, "Sacred Armor", Roll.Eth]); // Socket ethereal Sacred Armor + //Config.Recipes.push([Recipe.Socket.Armor, "Archon Plate", Roll.Eth]); // Socket ethereal Archon Plate - //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, 335, Roll.NonEth]); // Upgrade Bloodfist to Exceptional - //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, 337, Roll.NonEth]); // Upgrade Magefist to Exceptional - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 381, Roll.NonEth]); // Upgrade Bloodfist or Grave Palm to Elite - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 383, Roll.NonEth]); // Upgrade Magefist or Lavagout to Elite - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 389, Roll.NonEth]); // Upgrade Gore Rider to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, "Heavy Gloves", Roll.NonEth]); // Upgrade Bloodfist to Exceptional + //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, "Light Gauntlets", Roll.NonEth]); // Upgrade Magefist to Exceptional + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "Sharkskin Gloves", Roll.NonEth]); // Upgrade Bloodfist or Grave Palm to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "Battle Gauntlets", Roll.NonEth]); // Upgrade Magefist or Lavagout to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "War Boots", Roll.NonEth]); // Upgrade Gore Rider to Elite /* Runeword config. All recipes are available in Templates/Runewords.txt * Keep lines follow pickit format and any given runeword is tested vs ALL lines so you don't need to repeat them */ Config.MakeRunewords = false; // Set to true to enable runeword making/rerolling - //Config.Runewords.push([Runeword.Insight, 255]); // Thresher - //Config.Runewords.push([Runeword.Insight, 256]); // Cryptic Axe + //Config.Runewords.push([Runeword.Insight, "Thresher"]); // Make Insight Thresher + //Config.Runewords.push([Runeword.Insight, "Cryptic Axe"]); // Make Insight Cryptic Axe //Config.KeepRunewords.push("[type] == polearm # [meditationaura] == 17"); - //Config.Runewords.push([Runeword.Spirit, 447]); // Monarch - //Config.Runewords.push([Runeword.Spirit, 498]); // Sacred Targe + //Config.Runewords.push([Runeword.Spirit, "Monarch"]); // Make Spirit Monarch + //Config.Runewords.push([Runeword.Spirit, "Sacred Targe"]); // Make Spirit Sacred Targe //Config.KeepRunewords.push("[type] == shield || [type] == auricshields # [fcr] == 35"); @@ -366,15 +384,17 @@ function LoadConfig() { Config.DeathMessages = []; // Example: ["Watch out for that $killer, $name!"] Config.Congratulations = []; // Example: ["Congrats on level $level, $name!"] Config.ShitList = false; // Blacklist hostile players so they don't get invited to party. + Config.UnpartyShitlisted = false; // Leave party if someone invited a blacklisted player. // General config + Config.AutoMap = false; // Set to true to open automap at the beginning of the game. Config.LastMessage = ""; // Message or array of messages to say at the end of the run. Use $nextgame to say next game - "Next game: $nextgame" (works with lead entry point) Config.MinGameTime = 60; // Min game time in seconds. Bot will TP to town and stay in game if the run is completed before. Config.MaxGameTime = 0; // Maximum game time in seconds. Quit game when limit is reached. Config.TeleSwitch = false; // Switch to slot II when teleporting more than 1 node. Config.OpenChests = false; // Open chests. Controls key buying. Config.MiniShopBot = true; // Scan items in NPC shops. - Config.PacketShopping = false; // Use packets to shop. Imporves shopping speed. + Config.PacketShopping = false; // Use packets to shop. Improves shopping speed. Config.TownCheck = false; // Go to town if out of potions Config.LogExperience = false; // Print experience statistics in the manager. Config.PingQuit = [{Ping: 0, Duration: 0}]; // Quit if ping is over the given value for over the given time period in seconds. @@ -393,6 +413,7 @@ function LoadConfig() { Config.FBR = 0; // 0 - disable, 1 to 255 - set value of faster block recovery Config.IAS = 0; // 0 - disable, 1 to 255 - set value of increased attack speed Config.PacketCasting = 0; // 0 = disable, 1 = packet teleport, 2 = full packet casting. + Config.WaypointMenu = false; // Set to true for Single and private realms // Anti-hostile config Config.AntiHostile = false; // Enable anti-hostile @@ -405,6 +426,7 @@ function LoadConfig() { Config.StopOnDClone = true; // Go to town and idle as soon as Diablo walks the Earth Config.SoJWaitTime = 5; // Time in minutes to wait for another SoJ sale before leaving game. 0 = disabled Config.KillDclone = false; // Go to Palace Cellar 3 and try to kill Diablo Clone. Pointless if you already have Annihilus. + Config.DCloneQuit = false; // 1 = quit when Diablo walks, 2 = quit on soj sales, 0 = disabled // Monster skip config // Skip immune monsters. Possible options: "fire", "cold", "lightning", "poison", "physical", "magic". @@ -432,6 +454,14 @@ function LoadConfig() { Config.LowManaSkill[0] = -1; // Timed low mana skill. Config.LowManaSkill[1] = -1; // Untimed low mana skill. + /* Advanced Attack config. Allows custom skills to be used on custom monsters. + * Format: "Monster Name": [timed skill id, untimed skill id] + * Multiple entries are separated by commas + */ + Config.CustomAttack = { + //"Monster Name": [-1, -1] + }; + Config.Dodge = false; // Move away from monsters that get too close. Don't use with short-ranged attacks like Poison Dagger. Config.DodgeRange = 15; // Distance to keep from monsters. Config.DodgeHP = 100; // Dodge only if HP percent is less than or equal to Config.DodgeHP. 100 = always dodge. diff --git a/d2bs/kolbot/libs/config/Assassin.js b/d2bs/kolbot/libs/config/Assassin.js index 5d82ac185..6930ee343 100644 --- a/d2bs/kolbot/libs/config/Assassin.js +++ b/d2bs/kolbot/libs/config/Assassin.js @@ -86,6 +86,7 @@ function LoadConfig() { Config.Diablo.EntranceTP = "Entrance TP up"; Config.Diablo.StarTP = "Star TP up"; Config.Diablo.DiabloMsg = "Diablo"; + Scripts.SealLeader = false; // Clear a safe spot around seals and invite leechers in. Leechers should run SealLeecher script. Don't run with Diablo or FastDiablo. // *** act 5 *** Scripts.Pindleskin = false; @@ -124,15 +125,19 @@ function LoadConfig() { Config.Leader = ""; // Leader's ingame character name. Leave blank to try auto-detection (works in AutoBaal, Wakka, MFHelper) Config.QuitList = [""]; // List of character names to quit with. Example: Config.QuitList = ["MySorc", "MyDin"]; + Config.QuitListMode = 0; // 0 = use character names; 1 = use profile names (all profiles must run on the same computer). Scripts.TristramLeech = false; // Enters Tristram, attempts to stay close to the leader and will try and help kill. Scripts.TravincalLeech = false; // Enters portal at back of Travincal. Config.TravincalLeech.Helper = true; // If set to true the character will teleport to the stairs and help attack. Scripts.MFHelper = false; // Run the same MF run as the MFLeader. Leader must have Config.MFLeader = true - Scripts.Wakka = false; // Walking chaos leecher with auto leader assignment, stays at safe distance from the leeader + Scripts.Wakka = false; // Walking chaos leecher with auto leader assignment, stays at safe distance from the leader + Scripts.SealLeecher = false; // Enter safe portals to Chaos. Leader should run SealLeader. Scripts.DiabloHelper = false; // Chaos helper, kills monsters and doesn't open seals on its own. - Config.DiabloHelper.Wait = 120; // Seconds to wait for a runner to be in Chaos - Config.DiabloHelper.Entrance = true; // Start from entrance + Config.DiabloHelper.Wait = 120; // Seconds to wait for a runner to be in Chaos. If Config.Leader is set, it will wait only for the leader. + Config.DiabloHelper.Entrance = true; // Start from entrance. Set to false to start from star. + Config.DiabloHelper.SkipTP = false; // Don't wait for town portal and directly head to chaos. It will clear monsters around chaos entrance and wait for the runner. + Config.DiabloHelper.SkipIfBaal = false; // End script if there are party members in a Baal run. Scripts.AutoBaal = false; // Baal leecher with auto leader assignment Config.AutoBaal.FindShrine = false; // false = disabled, 1 = search after hot tp message, 2 = search as soon as leader is found Config.AutoBaal.LeechSpot = [15115, 5050]; // X, Y coords of Throne Room leech spot @@ -155,14 +160,21 @@ function LoadConfig() { Config.OrgTorch.WaitTimeout = 15; // Time in minutes to wait for keys before moving on Config.OrgTorch.UseSalvation = true; // Use Salvation aura on Mephisto (if possible) Config.OrgTorch.GetFade = false; // Get fade by standing in a fire. You MUST have Last Wish or Treachery on your character being worn. - Scripts.Rusher = false; // Rush bot alpha version (no questing yet, only rushing), for a list of commands, see Rusher.js + Scripts.Rusher = false; // Rush bot. For a list of commands, see Rusher.js Config.Rusher.WaitPlayerCount = 0; // Wait until game has a certain number of players (0 - don't wait, 8 - wait for full game). - Scripts.Rushee = false; // Automatic rushee, works with Rusher + Config.Rusher.Radament = false; // Do Radament quest. + Config.Rusher.LamEsen = false; // Do Lam Esen quest. + Config.Rusher.Izual = false; // Do Izual quest. + Config.Rusher.Shenk = false; // Do Shenk quest. + Config.Rusher.Anya = false; // Do Anya quest. + Config.Rusher.LastRun = ""; // End rush after this run. List of runs: http://pastebin.com/Uez3nZ6g + Scripts.Rushee = false; // Automatic rushee, works with Rusher. Set Rusher's character name as Config.Leader Config.Rushee.Quester = false; // Enter portals and get quest items. Config.Rushee.Bumper = false; // Do Ancients and Baal. Minimum levels: 20 - norm, 40 - nightmare Scripts.CrushTele = false; // classic rush teleporter. go to area of interest and press "-" numpad key Scripts.Questing = false; // solves missing quests (skill/stat+shenk) Scripts.Gamble = false; // Gambling system, other characters will mule gold into your game so you can gamble infinitely. See Gambling.js + Scripts.Crafting = false; // Crafting system, other characters will mule crafting ingredients. See CraftingSystem.js Scripts.GhostBusters = false; // Kill ghosts in most areas that contain them Scripts.Enchant = false; Config.Enchant.Triggers = ["chant", "cows", "wps"]; // Chat commands for enchant, cow level and waypoint giving @@ -173,17 +185,21 @@ function LoadConfig() { Config.IPHunter.IPList = []; // List of IPs to look for. example: [165, 201, 64] Config.IPHunter.GameLength = 3; // Number of minutes to stay in game if ip wasn't found Scripts.KillDclone = false; // Kill Diablo Clone by using Arcane Sanctuary waypoint. Diablo needs to walk the Earth in the game. - Scripts.ShopBot = false; // Fast waypoint-based shopbot - Config.ShopBot.ShopNPC = "Anya"; // Supported NPCs: Fara, Ormus, Anya, Elzix - // Scan only selected classids for maximum speed. See libs/config/templates/ShopBot.txt - Config.ShopBot.ScanIDs = [187, 188, 194, 195, 326, 327, 338, 373, 397, 443, 449]; - Scripts.ChestMania = false; // Open chests in configured areas + Scripts.ShopBot = false; // Shopbot script. Automatically uses shopbot.nip and ignores other pickits. + // Supported NPCs: Akara, Elzix, Fara, Drognan, Ormus, Asheara, Anya. Multiple NPCs are also supported, example: ["Elzix", "Fara"] + // Use common sense when combining NPCs. Shopping in different acts will probably lead to bugs. + Config.ShopBot.ShopNPC = "Anya"; + // Put item classid numbers or names to scan (remember to put quotes around names). Leave blank to scan ALL items. See libs/config/templates/ShopBot.txt + Config.ShopBot.ScanIDs = []; + Config.ShopBot.CycleDelay = 0; // Delay between shopping cycles in milliseconds, might help with crashes. + Config.ShopBot.QuitOnMatch = false; // Leave game as soon as an item is shopped. + Scripts.ChestMania = false; // Open chests in configured areas. See sdk/areas.txt Config.ChestMania.Act1 = [13, 14, 15, 16, 18, 19]; // List of act 1 areas to open chests in Config.ChestMania.Act2 = [55, 59, 65, 66, 67, 68, 69, 70, 71, 72]; // List of act 2 areas to open chests in Config.ChestMania.Act3 = [79, 80, 81, 92, 93, 84, 85, 90]; // List of act 3 areas to open chests in Config.ChestMania.Act4 = []; // List of act 4 areas to open chests in Config.ChestMania.Act5 = [115, 116, 119, 125, 126, 127]; // List of act 5 areas to open chests in - Scripts.ClearAnyArea = false; // Clear any area + Scripts.ClearAnyArea = false; // Clear any area. Uses Config.ClearType to determine which type of monsters to kill. Config.ClearAnyArea.AreaList = []; // List of area ids to clear. See sdk/areas.txt // *** Guest scripts *** @@ -269,13 +285,15 @@ function LoadConfig() { // Additional item info log settings. All info goes to \logs\ItemLog.txt Config.ItemInfo = false; // Log stashed, skipped (due to no space) or sold items. - Config.ItemInfoQuality = []; // The quality of sold items to log. + Config.ItemInfoQuality = []; // The quality of sold items to log. See NTItemAlias.dbl for values. Example: Config.ItemInfoQuality = [6, 7, 8]; // Item identification settings Config.CainID.Enable = false; // Identify items at Cain Config.CainID.MinGold = 2500000; // Minimum gold (stash + character) to have in order to use Cain. Config.CainID.MinUnids = 3; // Minimum number of unid items in order to use Cain. Config.FieldID = false; // Identify items in the field instead of going to town. + Config.DroppedItemsAnnounce.Enable = false; // Announce Dropped Items to in-game newbs + Config.DroppedItemsAnnounce.Quality = []; // Quality of item to announce. See NTItemAlias.dbl for values. Example: Config.DroppedItemsAnnounce.Quality = [6, 7, 8]; // Repair settings Config.CubeRepair = false; // Repair weapons with Ort and armor with Ral rune. Don't use it if you don't understand the risk of losing items. @@ -286,73 +304,73 @@ function LoadConfig() { Config.GambleGoldStart = 1000000; Config.GambleGoldStop = 500000; - // Check libs/NTItemAlias.dbl file for other item classids - Config.GambleItems.push(520); // Amulet - Config.GambleItems.push(522); // Ring - Config.GambleItems.push(418); // Circlet - Config.GambleItems.push(419); // Coronet + // List of item names or classids for gambling. Check libs/NTItemAlias.dbl file for other item classids. + Config.GambleItems.push("Amulet"); + Config.GambleItems.push("Ring"); + Config.GambleItems.push("Circlet"); + Config.GambleItems.push("Coronet"); - /* Cubing config. All recipe names are available in Templates/Cubing.txt - * The format is Config.Recipes.push([recipe_name, item_id, etherealness]). Etherealness is optional and only applies to some recipes. + /* Cubing config. All recipe names are available in Templates/Cubing.txt. For item names/classids check NTItemAlias.dbl + * The format is Config.Recipes.push([recipe_name, item_name_or_classid, etherealness]). Etherealness is optional and only applies to some recipes. */ Config.Cubing = false; // Set to true to enable cubing. // Ingredients for the following recipes will be auto-picked, for classids check libs/NTItemAlias.dbl - //Config.Recipes.push([Recipe.Gem, 560]); // perfect amethyst - //Config.Recipes.push([Recipe.Gem, 565]); // perfect topaz - //Config.Recipes.push([Recipe.Gem, 570]); // perfect sapphire - //Config.Recipes.push([Recipe.Gem, 575]); // perfect emerald - //Config.Recipes.push([Recipe.Gem, 580]); // perfect ruby - //Config.Recipes.push([Recipe.Gem, 585]); // perfect diamond - //Config.Recipes.push([Recipe.Gem, 600]); // perfect skull + //Config.Recipes.push([Recipe.Gem, "Flawless Amethyst"]); // Make Perfect Amethyst + //Config.Recipes.push([Recipe.Gem, "Flawless Topaz"]); // Make Perfect Topaz + //Config.Recipes.push([Recipe.Gem, "Flawless Sapphire"]); // Make Perfect Sapphire + //Config.Recipes.push([Recipe.Gem, "Flawless Emerald"]); // Make Perfect Emerald + //Config.Recipes.push([Recipe.Gem, "Flawless Ruby"]); // Make Perfect Ruby + //Config.Recipes.push([Recipe.Gem, "Flawless Diamond"]); // Make Perfect Diamond + //Config.Recipes.push([Recipe.Gem, "Flawless Skull"]); // Make Perfect Skull - //Config.Recipes.push([Recipe.Token]); // token of absolution - - //Config.Recipes.push([Recipe.Rune, 630]); // pul -> um - //Config.Recipes.push([Recipe.Rune, 631]); // um -> mal - //Config.Recipes.push([Recipe.Rune, 632]); // mal -> ist - //Config.Recipes.push([Recipe.Rune, 633]); // ist -> gul - //Config.Recipes.push([Recipe.Rune, 634]); // gul -> vex + //Config.Recipes.push([Recipe.Token]); // Make Token of Absolution + + //Config.Recipes.push([Recipe.Rune, "Pul Rune"]); // Upgrade Pul to Um + //Config.Recipes.push([Recipe.Rune, "Um Rune"]); // Upgrade Um to Mal + //Config.Recipes.push([Recipe.Rune, "Mal Rune"]); // Upgrade Mal to Ist + //Config.Recipes.push([Recipe.Rune, "Ist Rune"]); // Upgrade Ist to Gul + //Config.Recipes.push([Recipe.Rune, "Gul Rune"]); // Upgrade Gul to Vex //Config.Recipes.push([Recipe.Caster.Amulet]); // Craft Caster Amulet //Config.Recipes.push([Recipe.Blood.Ring]); // Craft Blood Ring - //Config.Recipes.push([Recipe.Blood.Helm, 424]); // Craft Blood Armet - //Config.Recipes.push([Recipe.HitPower.Gloves, 452]); // Craft Hit Power Vambraces + //Config.Recipes.push([Recipe.Blood.Helm, "Armet"]); // Craft Blood Armet + //Config.Recipes.push([Recipe.HitPower.Gloves, "Vambraces"]); // Craft Hit Power Vambraces // The gems not used by other recipes will be used for magic item rerolling. - //Config.Recipes.push([Recipe.Reroll.Magic, 421]); // Reroll magic Diadem - //Config.Recipes.push([Recipe.Reroll.Magic, 605]); // Reroll magic Grand Charm (ilvl 91+) + //Config.Recipes.push([Recipe.Reroll.Magic, "Diadem"]); // Reroll magic Diadem + //Config.Recipes.push([Recipe.Reroll.Magic, "Grand Charm"]); // Reroll magic Grand Charm (ilvl 91+) - //Config.Recipes.push([Recipe.Reroll.Rare, 421]); // Reroll rare Diadem + //Config.Recipes.push([Recipe.Reroll.Rare, "Diadem"]); // Reroll rare Diadem /* Base item for the following recipes must be in pickit. The rest of the ingredients will be auto-picked. * Use Roll.Eth, Roll.NonEth or Roll.All to determine what kind of base item to roll - ethereal, non-ethereal or all. */ - //Config.Recipes.push([Recipe.Socket.Weapon, 255, Roll.Eth]); // Socket ethereal Thresher - //Config.Recipes.push([Recipe.Socket.Weapon, 256, Roll.Eth]); // Socket ethereal Cryptic Axe - //Config.Recipes.push([Recipe.Socket.Armor, 442, Roll.Eth]); // Socket ethereal Sacred Armor - //Config.Recipes.push([Recipe.Socket.Armor, 443, Roll.Eth]); // Socket ethereal Archon Plate + //Config.Recipes.push([Recipe.Socket.Weapon, "Thresher", Roll.Eth]); // Socket ethereal Thresher + //Config.Recipes.push([Recipe.Socket.Weapon, "Cryptic Axe", Roll.Eth]); // Socket ethereal Cryptic Axe + //Config.Recipes.push([Recipe.Socket.Armor, "Sacred Armor", Roll.Eth]); // Socket ethereal Sacred Armor + //Config.Recipes.push([Recipe.Socket.Armor, "Archon Plate", Roll.Eth]); // Socket ethereal Archon Plate - //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, 335, Roll.NonEth]); // Upgrade Bloodfist to Exceptional - //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, 337, Roll.NonEth]); // Upgrade Magefist to Exceptional - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 381, Roll.NonEth]); // Upgrade Bloodfist or Grave Palm to Elite - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 383, Roll.NonEth]); // Upgrade Magefist or Lavagout to Elite - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 389, Roll.NonEth]); // Upgrade Gore Rider to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, "Heavy Gloves", Roll.NonEth]); // Upgrade Bloodfist to Exceptional + //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, "Light Gauntlets", Roll.NonEth]); // Upgrade Magefist to Exceptional + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "Sharkskin Gloves", Roll.NonEth]); // Upgrade Bloodfist or Grave Palm to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "Battle Gauntlets", Roll.NonEth]); // Upgrade Magefist or Lavagout to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "War Boots", Roll.NonEth]); // Upgrade Gore Rider to Elite /* Runeword config. All recipes are available in Templates/Runewords.txt * Keep lines follow pickit format and any given runeword is tested vs ALL lines so you don't need to repeat them */ Config.MakeRunewords = false; // Set to true to enable runeword making/rerolling - //Config.Runewords.push([Runeword.Insight, 255]); // Thresher - //Config.Runewords.push([Runeword.Insight, 256]); // Cryptic Axe + //Config.Runewords.push([Runeword.Insight, "Thresher"]); // Make Insight Thresher + //Config.Runewords.push([Runeword.Insight, "Cryptic Axe"]); // Make Insight Cryptic Axe //Config.KeepRunewords.push("[type] == polearm # [meditationaura] == 17"); - //Config.Runewords.push([Runeword.Spirit, 447]); // Monarch - //Config.Runewords.push([Runeword.Spirit, 498]); // Sacred Targe + //Config.Runewords.push([Runeword.Spirit, "Monarch"]); // Make Spirit Monarch + //Config.Runewords.push([Runeword.Spirit, "Sacred Targe"]); // Make Spirit Sacred Targe //Config.KeepRunewords.push("[type] == shield || [type] == auricshields # [fcr] == 35"); @@ -366,15 +384,17 @@ function LoadConfig() { Config.DeathMessages = []; // Example: ["Watch out for that $killer, $name!"] Config.Congratulations = []; // Example: ["Congrats on level $level, $name!"] Config.ShitList = false; // Blacklist hostile players so they don't get invited to party. + Config.UnpartyShitlisted = false; // Leave party if someone invited a blacklisted player. // General config + Config.AutoMap = false; // Set to true to open automap at the beginning of the game. Config.LastMessage = ""; // Message or array of messages to say at the end of the run. Use $nextgame to say next game - "Next game: $nextgame" (works with lead entry point) Config.MinGameTime = 60; // Min game time in seconds. Bot will TP to town and stay in game if the run is completed before. Config.MaxGameTime = 0; // Maximum game time in seconds. Quit game when limit is reached. Config.TeleSwitch = false; // Switch to slot II when teleporting more than 1 node. Config.OpenChests = false; // Open chests. Controls key buying. Config.MiniShopBot = true; // Scan items in NPC shops. - Config.PacketShopping = false; // Use packets to shop. Imporves shopping speed. + Config.PacketShopping = false; // Use packets to shop. Improves shopping speed. Config.TownCheck = false; // Go to town if out of potions Config.LogExperience = false; // Print experience statistics in the manager. Config.PingQuit = [{Ping: 0, Duration: 0}]; // Quit if ping is over the given value for over the given time period in seconds. @@ -393,6 +413,7 @@ function LoadConfig() { Config.FBR = 0; // 0 - disable, 1 to 255 - set value of faster block recovery Config.IAS = 0; // 0 - disable, 1 to 255 - set value of increased attack speed Config.PacketCasting = 0; // 0 = disable, 1 = packet teleport, 2 = full packet casting. + Config.WaypointMenu = false; // Set to true for Single and private realms // Anti-hostile config Config.AntiHostile = false; // Enable anti-hostile @@ -405,6 +426,7 @@ function LoadConfig() { Config.StopOnDClone = true; // Go to town and idle as soon as Diablo walks the Earth Config.SoJWaitTime = 5; // Time in minutes to wait for another SoJ sale before leaving game. 0 = disabled Config.KillDclone = false; // Go to Palace Cellar 3 and try to kill Diablo Clone. Pointless if you already have Annihilus. + Config.DCloneQuit = false; // 1 = quit when Diablo walks, 2 = quit on soj sales, 0 = disabled // Monster skip config // Skip immune monsters. Possible options: "fire", "cold", "lightning", "poison", "physical", "magic". @@ -419,7 +441,7 @@ function LoadConfig() { /* Attack config * To disable an attack, set it to -1 * Skills MUST be POSITIVE numbers. For reference see http://pastebin.com/baShRwWM - * Don't put traps here! Use Config. UseTraps, Config.Traps and Config.BossTraps + * Don't put LS/DS/WoF/WoI here! Use Config. UseTraps, Config.Traps and Config.BossTraps */ Config.AttackSkill[0] = -1; // Preattack skill. Config.AttackSkill[1] = -1; // Primary skill to bosses. @@ -433,6 +455,14 @@ function LoadConfig() { Config.LowManaSkill[0] = -1; // Timed low mana skill. Config.LowManaSkill[1] = -1; // Untimed low mana skill. + /* Advanced Attack config. Allows custom skills to be used on custom monsters. + * Format: "Monster Name": [timed skill id, untimed skill id] + * Multiple entries are separated by commas + */ + Config.CustomAttack = { + //"Monster Name": [-1, -1] + }; + Config.Dodge = false; // Move away from monsters that get too close. Don't use with short-ranged attacks like Poison Dagger. Config.DodgeRange = 15; // Distance to keep from monsters. Config.DodgeHP = 100; // Dodge only if HP percent is less than or equal to Config.DodgeHP. 100 = always dodge. diff --git a/d2bs/kolbot/libs/config/Barbarian.js b/d2bs/kolbot/libs/config/Barbarian.js index 435c33992..2e2ae7ea3 100644 --- a/d2bs/kolbot/libs/config/Barbarian.js +++ b/d2bs/kolbot/libs/config/Barbarian.js @@ -86,6 +86,7 @@ function LoadConfig() { Config.Diablo.EntranceTP = "Entrance TP up"; Config.Diablo.StarTP = "Star TP up"; Config.Diablo.DiabloMsg = "Diablo"; + Scripts.SealLeader = false; // Clear a safe spot around seals and invite leechers in. Leechers should run SealLeecher script. Don't run with Diablo or FastDiablo. // *** act 5 *** Scripts.Pindleskin = false; @@ -124,15 +125,19 @@ function LoadConfig() { Config.Leader = ""; // Leader's ingame character name. Leave blank to try auto-detection (works in AutoBaal, Wakka, MFHelper) Config.QuitList = [""]; // List of character names to quit with. Example: Config.QuitList = ["MySorc", "MyDin"]; + Config.QuitListMode = 0; // 0 = use character names; 1 = use profile names (all profiles must run on the same computer). Scripts.TristramLeech = false; // Enters Tristram, attempts to stay close to the leader and will try and help kill. Scripts.TravincalLeech = false; // Enters portal at back of Travincal. Config.TravincalLeech.Helper = true; // If set to true the character will teleport to the stairs and help attack. Scripts.MFHelper = false; // Run the same MF run as the MFLeader. Leader must have Config.MFLeader = true - Scripts.Wakka = false; // Walking chaos leecher with auto leader assignment, stays at safe distance from the leeader + Scripts.Wakka = false; // Walking chaos leecher with auto leader assignment, stays at safe distance from the leader + Scripts.SealLeecher = false; // Enter safe portals to Chaos. Leader should run SealLeader. Scripts.DiabloHelper = false; // Chaos helper, kills monsters and doesn't open seals on its own. - Config.DiabloHelper.Wait = 120; // Seconds to wait for a runner to be in Chaos - Config.DiabloHelper.Entrance = true; // Start from entrance + Config.DiabloHelper.Wait = 120; // Seconds to wait for a runner to be in Chaos. If Config.Leader is set, it will wait only for the leader. + Config.DiabloHelper.Entrance = true; // Start from entrance. Set to false to start from star. + Config.DiabloHelper.SkipTP = false; // Don't wait for town portal and directly head to chaos. It will clear monsters around chaos entrance and wait for the runner. + Config.DiabloHelper.SkipIfBaal = false; // End script if there are party members in a Baal run. Scripts.AutoBaal = false; // Baal leecher with auto leader assignment Config.AutoBaal.FindShrine = false; // false = disabled, 1 = search after hot tp message, 2 = search as soon as leader is found Config.AutoBaal.LeechSpot = [15115, 5050]; // X, Y coords of Throne Room leech spot @@ -155,14 +160,21 @@ function LoadConfig() { Config.OrgTorch.WaitTimeout = 15; // Time in minutes to wait for keys before moving on Config.OrgTorch.UseSalvation = true; // Use Salvation aura on Mephisto (if possible) Config.OrgTorch.GetFade = false; // Get fade by standing in a fire. You MUST have Last Wish or Treachery on your character being worn. - Scripts.Rusher = false; // Rush bot alpha version (no questing yet, only rushing), for a list of commands, see Rusher.js + Scripts.Rusher = false; // Rush bot. For a list of commands, see Rusher.js Config.Rusher.WaitPlayerCount = 0; // Wait until game has a certain number of players (0 - don't wait, 8 - wait for full game). - Scripts.Rushee = false; // Automatic rushee, works with Rusher + Config.Rusher.Radament = false; // Do Radament quest. + Config.Rusher.LamEsen = false; // Do Lam Esen quest. + Config.Rusher.Izual = false; // Do Izual quest. + Config.Rusher.Shenk = false; // Do Shenk quest. + Config.Rusher.Anya = false; // Do Anya quest. + Config.Rusher.LastRun = ""; // End rush after this run. List of runs: http://pastebin.com/Uez3nZ6g + Scripts.Rushee = false; // Automatic rushee, works with Rusher. Set Rusher's character name as Config.Leader Config.Rushee.Quester = false; // Enter portals and get quest items. Config.Rushee.Bumper = false; // Do Ancients and Baal. Minimum levels: 20 - norm, 40 - nightmare Scripts.CrushTele = false; // classic rush teleporter. go to area of interest and press "-" numpad key Scripts.Questing = false; // solves missing quests (skill/stat+shenk) Scripts.Gamble = false; // Gambling system, other characters will mule gold into your game so you can gamble infinitely. See Gambling.js + Scripts.Crafting = false; // Crafting system, other characters will mule crafting ingredients. See CraftingSystem.js Scripts.GhostBusters = false; // Kill ghosts in most areas that contain them Scripts.Enchant = false; Config.Enchant.Triggers = ["chant", "cows", "wps"]; // Chat commands for enchant, cow level and waypoint giving @@ -173,17 +185,21 @@ function LoadConfig() { Config.IPHunter.IPList = []; // List of IPs to look for. example: [165, 201, 64] Config.IPHunter.GameLength = 3; // Number of minutes to stay in game if ip wasn't found Scripts.KillDclone = false; // Kill Diablo Clone by using Arcane Sanctuary waypoint. Diablo needs to walk the Earth in the game. - Scripts.ShopBot = false; // Fast waypoint-based shopbot - Config.ShopBot.ShopNPC = "Anya"; // Supported NPCs: Fara, Ormus, Anya, Elzix - // Scan only selected classids for maximum speed. See libs/config/templates/ShopBot.txt - Config.ShopBot.ScanIDs = [187, 188, 194, 195, 326, 327, 338, 373, 397, 443, 449]; - Scripts.ChestMania = false; // Open chests in configured areas + Scripts.ShopBot = false; // Shopbot script. Automatically uses shopbot.nip and ignores other pickits. + // Supported NPCs: Akara, Elzix, Fara, Drognan, Ormus, Asheara, Anya. Multiple NPCs are also supported, example: ["Elzix", "Fara"] + // Use common sense when combining NPCs. Shopping in different acts will probably lead to bugs. + Config.ShopBot.ShopNPC = "Anya"; + // Put item classid numbers or names to scan (remember to put quotes around names). Leave blank to scan ALL items. See libs/config/templates/ShopBot.txt + Config.ShopBot.ScanIDs = []; + Config.ShopBot.CycleDelay = 0; // Delay between shopping cycles in milliseconds, might help with crashes. + Config.ShopBot.QuitOnMatch = false; // Leave game as soon as an item is shopped. + Scripts.ChestMania = false; // Open chests in configured areas. See sdk/areas.txt Config.ChestMania.Act1 = [13, 14, 15, 16, 18, 19]; // List of act 1 areas to open chests in Config.ChestMania.Act2 = [55, 59, 65, 66, 67, 68, 69, 70, 71, 72]; // List of act 2 areas to open chests in Config.ChestMania.Act3 = [79, 80, 81, 92, 93, 84, 85, 90]; // List of act 3 areas to open chests in Config.ChestMania.Act4 = []; // List of act 4 areas to open chests in Config.ChestMania.Act5 = [115, 116, 119, 125, 126, 127]; // List of act 5 areas to open chests in - Scripts.ClearAnyArea = false; // Clear any area + Scripts.ClearAnyArea = false; // Clear any area. Uses Config.ClearType to determine which type of monsters to kill. Config.ClearAnyArea.AreaList = []; // List of area ids to clear. See sdk/areas.txt // *** Guest scripts *** @@ -269,13 +285,15 @@ function LoadConfig() { // Additional item info log settings. All info goes to \logs\ItemLog.txt Config.ItemInfo = false; // Log stashed, skipped (due to no space) or sold items. - Config.ItemInfoQuality = []; // The quality of sold items to log. + Config.ItemInfoQuality = []; // The quality of sold items to log. See NTItemAlias.dbl for values. Example: Config.ItemInfoQuality = [6, 7, 8]; // Item identification settings Config.CainID.Enable = false; // Identify items at Cain Config.CainID.MinGold = 2500000; // Minimum gold (stash + character) to have in order to use Cain. Config.CainID.MinUnids = 3; // Minimum number of unid items in order to use Cain. Config.FieldID = false; // Identify items in the field instead of going to town. + Config.DroppedItemsAnnounce.Enable = false; // Announce Dropped Items to in-game newbs + Config.DroppedItemsAnnounce.Quality = []; // Quality of item to announce. See NTItemAlias.dbl for values. Example: Config.DroppedItemsAnnounce.Quality = [6, 7, 8]; // Repair settings Config.CubeRepair = false; // Repair weapons with Ort and armor with Ral rune. Don't use it if you don't understand the risk of losing items. @@ -286,73 +304,73 @@ function LoadConfig() { Config.GambleGoldStart = 1000000; Config.GambleGoldStop = 500000; - // Check libs/NTItemAlias.dbl file for other item classids - Config.GambleItems.push(520); // Amulet - Config.GambleItems.push(522); // Ring - Config.GambleItems.push(418); // Circlet - Config.GambleItems.push(419); // Coronet + // List of item names or classids for gambling. Check libs/NTItemAlias.dbl file for other item classids. + Config.GambleItems.push("Amulet"); + Config.GambleItems.push("Ring"); + Config.GambleItems.push("Circlet"); + Config.GambleItems.push("Coronet"); - /* Cubing config. All recipe names are available in Templates/Cubing.txt - * The format is Config.Recipes.push([recipe_name, item_id, etherealness]). Etherealness is optional and only applies to some recipes. + /* Cubing config. All recipe names are available in Templates/Cubing.txt. For item names/classids check NTItemAlias.dbl + * The format is Config.Recipes.push([recipe_name, item_name_or_classid, etherealness]). Etherealness is optional and only applies to some recipes. */ Config.Cubing = false; // Set to true to enable cubing. // Ingredients for the following recipes will be auto-picked, for classids check libs/NTItemAlias.dbl - //Config.Recipes.push([Recipe.Gem, 560]); // perfect amethyst - //Config.Recipes.push([Recipe.Gem, 565]); // perfect topaz - //Config.Recipes.push([Recipe.Gem, 570]); // perfect sapphire - //Config.Recipes.push([Recipe.Gem, 575]); // perfect emerald - //Config.Recipes.push([Recipe.Gem, 580]); // perfect ruby - //Config.Recipes.push([Recipe.Gem, 585]); // perfect diamond - //Config.Recipes.push([Recipe.Gem, 600]); // perfect skull + //Config.Recipes.push([Recipe.Gem, "Flawless Amethyst"]); // Make Perfect Amethyst + //Config.Recipes.push([Recipe.Gem, "Flawless Topaz"]); // Make Perfect Topaz + //Config.Recipes.push([Recipe.Gem, "Flawless Sapphire"]); // Make Perfect Sapphire + //Config.Recipes.push([Recipe.Gem, "Flawless Emerald"]); // Make Perfect Emerald + //Config.Recipes.push([Recipe.Gem, "Flawless Ruby"]); // Make Perfect Ruby + //Config.Recipes.push([Recipe.Gem, "Flawless Diamond"]); // Make Perfect Diamond + //Config.Recipes.push([Recipe.Gem, "Flawless Skull"]); // Make Perfect Skull - //Config.Recipes.push([Recipe.Token]); // token of absolution - - //Config.Recipes.push([Recipe.Rune, 630]); // pul -> um - //Config.Recipes.push([Recipe.Rune, 631]); // um -> mal - //Config.Recipes.push([Recipe.Rune, 632]); // mal -> ist - //Config.Recipes.push([Recipe.Rune, 633]); // ist -> gul - //Config.Recipes.push([Recipe.Rune, 634]); // gul -> vex + //Config.Recipes.push([Recipe.Token]); // Make Token of Absolution + + //Config.Recipes.push([Recipe.Rune, "Pul Rune"]); // Upgrade Pul to Um + //Config.Recipes.push([Recipe.Rune, "Um Rune"]); // Upgrade Um to Mal + //Config.Recipes.push([Recipe.Rune, "Mal Rune"]); // Upgrade Mal to Ist + //Config.Recipes.push([Recipe.Rune, "Ist Rune"]); // Upgrade Ist to Gul + //Config.Recipes.push([Recipe.Rune, "Gul Rune"]); // Upgrade Gul to Vex //Config.Recipes.push([Recipe.Caster.Amulet]); // Craft Caster Amulet //Config.Recipes.push([Recipe.Blood.Ring]); // Craft Blood Ring - //Config.Recipes.push([Recipe.Blood.Helm, 424]); // Craft Blood Armet - //Config.Recipes.push([Recipe.HitPower.Gloves, 452]); // Craft Hit Power Vambraces + //Config.Recipes.push([Recipe.Blood.Helm, "Armet"]); // Craft Blood Armet + //Config.Recipes.push([Recipe.HitPower.Gloves, "Vambraces"]); // Craft Hit Power Vambraces // The gems not used by other recipes will be used for magic item rerolling. - //Config.Recipes.push([Recipe.Reroll.Magic, 421]); // Reroll magic Diadem - //Config.Recipes.push([Recipe.Reroll.Magic, 605]); // Reroll magic Grand Charm (ilvl 91+) + //Config.Recipes.push([Recipe.Reroll.Magic, "Diadem"]); // Reroll magic Diadem + //Config.Recipes.push([Recipe.Reroll.Magic, "Grand Charm"]); // Reroll magic Grand Charm (ilvl 91+) - //Config.Recipes.push([Recipe.Reroll.Rare, 421]); // Reroll rare Diadem + //Config.Recipes.push([Recipe.Reroll.Rare, "Diadem"]); // Reroll rare Diadem /* Base item for the following recipes must be in pickit. The rest of the ingredients will be auto-picked. * Use Roll.Eth, Roll.NonEth or Roll.All to determine what kind of base item to roll - ethereal, non-ethereal or all. */ - //Config.Recipes.push([Recipe.Socket.Weapon, 255, Roll.Eth]); // Socket ethereal Thresher - //Config.Recipes.push([Recipe.Socket.Weapon, 256, Roll.Eth]); // Socket ethereal Cryptic Axe - //Config.Recipes.push([Recipe.Socket.Armor, 442, Roll.Eth]); // Socket ethereal Sacred Armor - //Config.Recipes.push([Recipe.Socket.Armor, 443, Roll.Eth]); // Socket ethereal Archon Plate + //Config.Recipes.push([Recipe.Socket.Weapon, "Thresher", Roll.Eth]); // Socket ethereal Thresher + //Config.Recipes.push([Recipe.Socket.Weapon, "Cryptic Axe", Roll.Eth]); // Socket ethereal Cryptic Axe + //Config.Recipes.push([Recipe.Socket.Armor, "Sacred Armor", Roll.Eth]); // Socket ethereal Sacred Armor + //Config.Recipes.push([Recipe.Socket.Armor, "Archon Plate", Roll.Eth]); // Socket ethereal Archon Plate - //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, 335, Roll.NonEth]); // Upgrade Bloodfist to Exceptional - //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, 337, Roll.NonEth]); // Upgrade Magefist to Exceptional - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 381, Roll.NonEth]); // Upgrade Bloodfist or Grave Palm to Elite - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 383, Roll.NonEth]); // Upgrade Magefist or Lavagout to Elite - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 389, Roll.NonEth]); // Upgrade Gore Rider to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, "Heavy Gloves", Roll.NonEth]); // Upgrade Bloodfist to Exceptional + //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, "Light Gauntlets", Roll.NonEth]); // Upgrade Magefist to Exceptional + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "Sharkskin Gloves", Roll.NonEth]); // Upgrade Bloodfist or Grave Palm to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "Battle Gauntlets", Roll.NonEth]); // Upgrade Magefist or Lavagout to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "War Boots", Roll.NonEth]); // Upgrade Gore Rider to Elite /* Runeword config. All recipes are available in Templates/Runewords.txt * Keep lines follow pickit format and any given runeword is tested vs ALL lines so you don't need to repeat them */ Config.MakeRunewords = false; // Set to true to enable runeword making/rerolling - //Config.Runewords.push([Runeword.Insight, 255]); // Thresher - //Config.Runewords.push([Runeword.Insight, 256]); // Cryptic Axe + //Config.Runewords.push([Runeword.Insight, "Thresher"]); // Make Insight Thresher + //Config.Runewords.push([Runeword.Insight, "Cryptic Axe"]); // Make Insight Cryptic Axe //Config.KeepRunewords.push("[type] == polearm # [meditationaura] == 17"); - //Config.Runewords.push([Runeword.Spirit, 447]); // Monarch - //Config.Runewords.push([Runeword.Spirit, 498]); // Sacred Targe + //Config.Runewords.push([Runeword.Spirit, "Monarch"]); // Make Spirit Monarch + //Config.Runewords.push([Runeword.Spirit, "Sacred Targe"]); // Make Spirit Sacred Targe //Config.KeepRunewords.push("[type] == shield || [type] == auricshields # [fcr] == 35"); @@ -366,15 +384,17 @@ function LoadConfig() { Config.DeathMessages = []; // Example: ["Watch out for that $killer, $name!"] Config.Congratulations = []; // Example: ["Congrats on level $level, $name!"] Config.ShitList = false; // Blacklist hostile players so they don't get invited to party. + Config.UnpartyShitlisted = false; // Leave party if someone invited a blacklisted player. // General config + Config.AutoMap = false; // Set to true to open automap at the beginning of the game. Config.LastMessage = ""; // Message or array of messages to say at the end of the run. Use $nextgame to say next game - "Next game: $nextgame" (works with lead entry point) Config.MinGameTime = 60; // Min game time in seconds. Bot will TP to town and stay in game if the run is completed before. Config.MaxGameTime = 0; // Maximum game time in seconds. Quit game when limit is reached. Config.TeleSwitch = false; // Switch to slot II when teleporting more than 1 node. Config.OpenChests = false; // Open chests. Controls key buying. Config.MiniShopBot = true; // Scan items in NPC shops. - Config.PacketShopping = false; // Use packets to shop. Imporves shopping speed. + Config.PacketShopping = false; // Use packets to shop. Improves shopping speed. Config.TownCheck = false; // Go to town if out of potions Config.LogExperience = false; // Print experience statistics in the manager. Config.PingQuit = [{Ping: 0, Duration: 0}]; // Quit if ping is over the given value for over the given time period in seconds. @@ -393,6 +413,7 @@ function LoadConfig() { Config.FBR = 0; // 0 - disable, 1 to 255 - set value of faster block recovery Config.IAS = 0; // 0 - disable, 1 to 255 - set value of increased attack speed Config.PacketCasting = 0; // 0 = disable, 1 = packet teleport, 2 = full packet casting. + Config.WaypointMenu = false; // Set to true for Single and private realms // Anti-hostile config Config.AntiHostile = false; // Enable anti-hostile @@ -405,6 +426,7 @@ function LoadConfig() { Config.StopOnDClone = true; // Go to town and idle as soon as Diablo walks the Earth Config.SoJWaitTime = 5; // Time in minutes to wait for another SoJ sale before leaving game. 0 = disabled Config.KillDclone = false; // Go to Palace Cellar 3 and try to kill Diablo Clone. Pointless if you already have Annihilus. + Config.DCloneQuit = false; // 1 = quit when Diablo walks, 2 = quit on soj sales, 0 = disabled // Monster skip config // Skip immune monsters. Possible options: "fire", "cold", "lightning", "poison", "physical", "magic". @@ -429,6 +451,14 @@ function LoadConfig() { // Low mana skills - these will be used if main skills can't be cast. Config.LowManaSkill[0] = -1; // Low mana skill. + /* Advanced Attack config. Allows custom skills to be used on custom monsters. + * Format: "Monster Name": [attack skill id] + * Multiple entries are separated by commas + */ + Config.CustomAttack = { + //"Monster Name": [-1] + }; + Config.BossPriority = false; // Set to true to attack Unique/SuperUnique monsters first when clearing Config.ClearType = 0xF; // Monster spectype to kill in level clear scripts (ie. Mausoleum). 0xF = skip normal, 0x7 = champions/bosses, 0 = all diff --git a/d2bs/kolbot/libs/config/Druid.js b/d2bs/kolbot/libs/config/Druid.js index 64de70b5f..973a20e1e 100644 --- a/d2bs/kolbot/libs/config/Druid.js +++ b/d2bs/kolbot/libs/config/Druid.js @@ -86,6 +86,7 @@ function LoadConfig() { Config.Diablo.EntranceTP = "Entrance TP up"; Config.Diablo.StarTP = "Star TP up"; Config.Diablo.DiabloMsg = "Diablo"; + Scripts.SealLeader = false; // Clear a safe spot around seals and invite leechers in. Leechers should run SealLeecher script. Don't run with Diablo or FastDiablo. // *** act 5 *** Scripts.Pindleskin = false; @@ -124,15 +125,19 @@ function LoadConfig() { Config.Leader = ""; // Leader's ingame character name. Leave blank to try auto-detection (works in AutoBaal, Wakka, MFHelper) Config.QuitList = [""]; // List of character names to quit with. Example: Config.QuitList = ["MySorc", "MyDin"]; + Config.QuitListMode = 0; // 0 = use character names; 1 = use profile names (all profiles must run on the same computer). Scripts.TristramLeech = false; // Enters Tristram, attempts to stay close to the leader and will try and help kill. Scripts.TravincalLeech = false; // Enters portal at back of Travincal. Config.TravincalLeech.Helper = true; // If set to true the character will teleport to the stairs and help attack. Scripts.MFHelper = false; // Run the same MF run as the MFLeader. Leader must have Config.MFLeader = true - Scripts.Wakka = false; // Walking chaos leecher with auto leader assignment, stays at safe distance from the leeader + Scripts.Wakka = false; // Walking chaos leecher with auto leader assignment, stays at safe distance from the leader + Scripts.SealLeecher = false; // Enter safe portals to Chaos. Leader should run SealLeader. Scripts.DiabloHelper = false; // Chaos helper, kills monsters and doesn't open seals on its own. - Config.DiabloHelper.Wait = 120; // Seconds to wait for a runner to be in Chaos - Config.DiabloHelper.Entrance = true; // Start from entrance + Config.DiabloHelper.Wait = 120; // Seconds to wait for a runner to be in Chaos. If Config.Leader is set, it will wait only for the leader. + Config.DiabloHelper.Entrance = true; // Start from entrance. Set to false to start from star. + Config.DiabloHelper.SkipTP = false; // Don't wait for town portal and directly head to chaos. It will clear monsters around chaos entrance and wait for the runner. + Config.DiabloHelper.SkipIfBaal = false; // End script if there are party members in a Baal run. Scripts.AutoBaal = false; // Baal leecher with auto leader assignment Config.AutoBaal.FindShrine = false; // false = disabled, 1 = search after hot tp message, 2 = search as soon as leader is found Config.AutoBaal.LeechSpot = [15115, 5050]; // X, Y coords of Throne Room leech spot @@ -155,14 +160,21 @@ function LoadConfig() { Config.OrgTorch.WaitTimeout = 15; // Time in minutes to wait for keys before moving on Config.OrgTorch.UseSalvation = true; // Use Salvation aura on Mephisto (if possible) Config.OrgTorch.GetFade = false; // Get fade by standing in a fire. You MUST have Last Wish or Treachery on your character being worn. - Scripts.Rusher = false; // Rush bot alpha version (no questing yet, only rushing), for a list of commands, see Rusher.js + Scripts.Rusher = false; // Rush bot. For a list of commands, see Rusher.js Config.Rusher.WaitPlayerCount = 0; // Wait until game has a certain number of players (0 - don't wait, 8 - wait for full game). - Scripts.Rushee = false; // Automatic rushee, works with Rusher + Config.Rusher.Radament = false; // Do Radament quest. + Config.Rusher.LamEsen = false; // Do Lam Esen quest. + Config.Rusher.Izual = false; // Do Izual quest. + Config.Rusher.Shenk = false; // Do Shenk quest. + Config.Rusher.Anya = false; // Do Anya quest. + Config.Rusher.LastRun = ""; // End rush after this run. List of runs: http://pastebin.com/Uez3nZ6g + Scripts.Rushee = false; // Automatic rushee, works with Rusher. Set Rusher's character name as Config.Leader Config.Rushee.Quester = false; // Enter portals and get quest items. Config.Rushee.Bumper = false; // Do Ancients and Baal. Minimum levels: 20 - norm, 40 - nightmare Scripts.CrushTele = false; // classic rush teleporter. go to area of interest and press "-" numpad key Scripts.Questing = false; // solves missing quests (skill/stat+shenk) Scripts.Gamble = false; // Gambling system, other characters will mule gold into your game so you can gamble infinitely. See Gambling.js + Scripts.Crafting = false; // Crafting system, other characters will mule crafting ingredients. See CraftingSystem.js Scripts.GhostBusters = false; // Kill ghosts in most areas that contain them Scripts.Enchant = false; Config.Enchant.Triggers = ["chant", "cows", "wps"]; // Chat commands for enchant, cow level and waypoint giving @@ -172,20 +184,25 @@ function LoadConfig() { Scripts.IPHunter = false; Config.IPHunter.IPList = []; // List of IPs to look for. example: [165, 201, 64] Config.IPHunter.GameLength = 3; // Number of minutes to stay in game if ip wasn't found - Scripts.ShopBot = false; // Fast waypoint-based shopbot - Config.ShopBot.ShopNPC = "Anya"; // Supported NPCs: Fara, Ormus, Anya, Elzix - // Scan only selected classids for maximum speed. See libs/config/templates/ShopBot.txt - Config.ShopBot.ScanIDs = [187, 188, 194, 195, 326, 327, 338, 373, 397, 443, 449]; - Scripts.ChestMania = false; // Open chests in configured areas + Scripts.KillDclone = false; // Kill Diablo Clone by using Arcane Sanctuary waypoint. Diablo needs to walk the Earth in the game. + Scripts.ShopBot = false; // Shopbot script. Automatically uses shopbot.nip and ignores other pickits. + // Supported NPCs: Akara, Elzix, Fara, Drognan, Ormus, Asheara, Anya. Multiple NPCs are also supported, example: ["Elzix", "Fara"] + // Use common sense when combining NPCs. Shopping in different acts will probably lead to bugs. + Config.ShopBot.ShopNPC = "Anya"; + // Put item classid numbers or names to scan (remember to put quotes around names). Leave blank to scan ALL items. See libs/config/templates/ShopBot.txt + Config.ShopBot.ScanIDs = []; + Config.ShopBot.CycleDelay = 0; // Delay between shopping cycles in milliseconds, might help with crashes. + Config.ShopBot.QuitOnMatch = false; // Leave game as soon as an item is shopped. + Scripts.ChestMania = false; // Open chests in configured areas. See sdk/areas.txt Config.ChestMania.Act1 = [13, 14, 15, 16, 18, 19]; // List of act 1 areas to open chests in Config.ChestMania.Act2 = [55, 59, 65, 66, 67, 68, 69, 70, 71, 72]; // List of act 2 areas to open chests in Config.ChestMania.Act3 = [79, 80, 81, 92, 93, 84, 85, 90]; // List of act 3 areas to open chests in Config.ChestMania.Act4 = []; // List of act 4 areas to open chests in Config.ChestMania.Act5 = [115, 116, 119, 125, 126, 127]; // List of act 5 areas to open chests in - Scripts.ClearAnyArea = false; // Clear any area + Scripts.ClearAnyArea = false; // Clear any area. Uses Config.ClearType to determine which type of monsters to kill. Config.ClearAnyArea.AreaList = []; // List of area ids to clear. See sdk/areas.txt - // *** Guest scripts *** + // *** Guest scripts *** // Baal Assistant by YourGreatestMember Scripts.BaalAssistant = false; // Used to leech or help in baal runs. @@ -268,13 +285,15 @@ function LoadConfig() { // Additional item info log settings. All info goes to \logs\ItemLog.txt Config.ItemInfo = false; // Log stashed, skipped (due to no space) or sold items. - Config.ItemInfoQuality = []; // The quality of sold items to log. + Config.ItemInfoQuality = []; // The quality of sold items to log. See NTItemAlias.dbl for values. Example: Config.ItemInfoQuality = [6, 7, 8]; // Item identification settings Config.CainID.Enable = false; // Identify items at Cain Config.CainID.MinGold = 2500000; // Minimum gold (stash + character) to have in order to use Cain. Config.CainID.MinUnids = 3; // Minimum number of unid items in order to use Cain. Config.FieldID = false; // Identify items in the field instead of going to town. + Config.DroppedItemsAnnounce.Enable = false; // Announce Dropped Items to in-game newbs + Config.DroppedItemsAnnounce.Quality = []; // Quality of item to announce. See NTItemAlias.dbl for values. Example: Config.DroppedItemsAnnounce.Quality = [6, 7, 8]; // Repair settings Config.CubeRepair = false; // Repair weapons with Ort and armor with Ral rune. Don't use it if you don't understand the risk of losing items. @@ -285,73 +304,73 @@ function LoadConfig() { Config.GambleGoldStart = 1000000; Config.GambleGoldStop = 500000; - // Check libs/NTItemAlias.dbl file for other item classids - Config.GambleItems.push(520); // Amulet - Config.GambleItems.push(522); // Ring - Config.GambleItems.push(418); // Circlet - Config.GambleItems.push(419); // Coronet + // List of item names or classids for gambling. Check libs/NTItemAlias.dbl file for other item classids. + Config.GambleItems.push("Amulet"); + Config.GambleItems.push("Ring"); + Config.GambleItems.push("Circlet"); + Config.GambleItems.push("Coronet"); - /* Cubing config. All recipe names are available in Templates/Cubing.txt - * The format is Config.Recipes.push([recipe_name, item_id, etherealness]). Etherealness is optional and only applies to some recipes. + /* Cubing config. All recipe names are available in Templates/Cubing.txt. For item names/classids check NTItemAlias.dbl + * The format is Config.Recipes.push([recipe_name, item_name_or_classid, etherealness]). Etherealness is optional and only applies to some recipes. */ Config.Cubing = false; // Set to true to enable cubing. // Ingredients for the following recipes will be auto-picked, for classids check libs/NTItemAlias.dbl - //Config.Recipes.push([Recipe.Gem, 560]); // perfect amethyst - //Config.Recipes.push([Recipe.Gem, 565]); // perfect topaz - //Config.Recipes.push([Recipe.Gem, 570]); // perfect sapphire - //Config.Recipes.push([Recipe.Gem, 575]); // perfect emerald - //Config.Recipes.push([Recipe.Gem, 580]); // perfect ruby - //Config.Recipes.push([Recipe.Gem, 585]); // perfect diamond - //Config.Recipes.push([Recipe.Gem, 600]); // perfect skull + //Config.Recipes.push([Recipe.Gem, "Flawless Amethyst"]); // Make Perfect Amethyst + //Config.Recipes.push([Recipe.Gem, "Flawless Topaz"]); // Make Perfect Topaz + //Config.Recipes.push([Recipe.Gem, "Flawless Sapphire"]); // Make Perfect Sapphire + //Config.Recipes.push([Recipe.Gem, "Flawless Emerald"]); // Make Perfect Emerald + //Config.Recipes.push([Recipe.Gem, "Flawless Ruby"]); // Make Perfect Ruby + //Config.Recipes.push([Recipe.Gem, "Flawless Diamond"]); // Make Perfect Diamond + //Config.Recipes.push([Recipe.Gem, "Flawless Skull"]); // Make Perfect Skull - //Config.Recipes.push([Recipe.Token]); // token of absolution - - //Config.Recipes.push([Recipe.Rune, 630]); // pul -> um - //Config.Recipes.push([Recipe.Rune, 631]); // um -> mal - //Config.Recipes.push([Recipe.Rune, 632]); // mal -> ist - //Config.Recipes.push([Recipe.Rune, 633]); // ist -> gul - //Config.Recipes.push([Recipe.Rune, 634]); // gul -> vex + //Config.Recipes.push([Recipe.Token]); // Make Token of Absolution + + //Config.Recipes.push([Recipe.Rune, "Pul Rune"]); // Upgrade Pul to Um + //Config.Recipes.push([Recipe.Rune, "Um Rune"]); // Upgrade Um to Mal + //Config.Recipes.push([Recipe.Rune, "Mal Rune"]); // Upgrade Mal to Ist + //Config.Recipes.push([Recipe.Rune, "Ist Rune"]); // Upgrade Ist to Gul + //Config.Recipes.push([Recipe.Rune, "Gul Rune"]); // Upgrade Gul to Vex //Config.Recipes.push([Recipe.Caster.Amulet]); // Craft Caster Amulet //Config.Recipes.push([Recipe.Blood.Ring]); // Craft Blood Ring - //Config.Recipes.push([Recipe.Blood.Helm, 424]); // Craft Blood Armet - //Config.Recipes.push([Recipe.HitPower.Gloves, 452]); // Craft Hit Power Vambraces + //Config.Recipes.push([Recipe.Blood.Helm, "Armet"]); // Craft Blood Armet + //Config.Recipes.push([Recipe.HitPower.Gloves, "Vambraces"]); // Craft Hit Power Vambraces // The gems not used by other recipes will be used for magic item rerolling. - //Config.Recipes.push([Recipe.Reroll.Magic, 421]); // Reroll magic Diadem - //Config.Recipes.push([Recipe.Reroll.Magic, 605]); // Reroll magic Grand Charm (ilvl 91+) + //Config.Recipes.push([Recipe.Reroll.Magic, "Diadem"]); // Reroll magic Diadem + //Config.Recipes.push([Recipe.Reroll.Magic, "Grand Charm"]); // Reroll magic Grand Charm (ilvl 91+) - //Config.Recipes.push([Recipe.Reroll.Rare, 421]); // Reroll rare Diadem + //Config.Recipes.push([Recipe.Reroll.Rare, "Diadem"]); // Reroll rare Diadem /* Base item for the following recipes must be in pickit. The rest of the ingredients will be auto-picked. * Use Roll.Eth, Roll.NonEth or Roll.All to determine what kind of base item to roll - ethereal, non-ethereal or all. */ - //Config.Recipes.push([Recipe.Socket.Weapon, 255, Roll.Eth]); // Socket ethereal Thresher - //Config.Recipes.push([Recipe.Socket.Weapon, 256, Roll.Eth]); // Socket ethereal Cryptic Axe - //Config.Recipes.push([Recipe.Socket.Armor, 442, Roll.Eth]); // Socket ethereal Sacred Armor - //Config.Recipes.push([Recipe.Socket.Armor, 443, Roll.Eth]); // Socket ethereal Archon Plate + //Config.Recipes.push([Recipe.Socket.Weapon, "Thresher", Roll.Eth]); // Socket ethereal Thresher + //Config.Recipes.push([Recipe.Socket.Weapon, "Cryptic Axe", Roll.Eth]); // Socket ethereal Cryptic Axe + //Config.Recipes.push([Recipe.Socket.Armor, "Sacred Armor", Roll.Eth]); // Socket ethereal Sacred Armor + //Config.Recipes.push([Recipe.Socket.Armor, "Archon Plate", Roll.Eth]); // Socket ethereal Archon Plate - //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, 335, Roll.NonEth]); // Upgrade Bloodfist to Exceptional - //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, 337, Roll.NonEth]); // Upgrade Magefist to Exceptional - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 381, Roll.NonEth]); // Upgrade Bloodfist or Grave Palm to Elite - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 383, Roll.NonEth]); // Upgrade Magefist or Lavagout to Elite - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 389, Roll.NonEth]); // Upgrade Gore Rider to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, "Heavy Gloves", Roll.NonEth]); // Upgrade Bloodfist to Exceptional + //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, "Light Gauntlets", Roll.NonEth]); // Upgrade Magefist to Exceptional + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "Sharkskin Gloves", Roll.NonEth]); // Upgrade Bloodfist or Grave Palm to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "Battle Gauntlets", Roll.NonEth]); // Upgrade Magefist or Lavagout to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "War Boots", Roll.NonEth]); // Upgrade Gore Rider to Elite /* Runeword config. All recipes are available in Templates/Runewords.txt * Keep lines follow pickit format and any given runeword is tested vs ALL lines so you don't need to repeat them */ Config.MakeRunewords = false; // Set to true to enable runeword making/rerolling - //Config.Runewords.push([Runeword.Insight, 255]); // Thresher - //Config.Runewords.push([Runeword.Insight, 256]); // Cryptic Axe + //Config.Runewords.push([Runeword.Insight, "Thresher"]); // Make Insight Thresher + //Config.Runewords.push([Runeword.Insight, "Cryptic Axe"]); // Make Insight Cryptic Axe //Config.KeepRunewords.push("[type] == polearm # [meditationaura] == 17"); - //Config.Runewords.push([Runeword.Spirit, 447]); // Monarch - //Config.Runewords.push([Runeword.Spirit, 498]); // Sacred Targe + //Config.Runewords.push([Runeword.Spirit, "Monarch"]); // Make Spirit Monarch + //Config.Runewords.push([Runeword.Spirit, "Sacred Targe"]); // Make Spirit Sacred Targe //Config.KeepRunewords.push("[type] == shield || [type] == auricshields # [fcr] == 35"); @@ -365,15 +384,17 @@ function LoadConfig() { Config.DeathMessages = []; // Example: ["Watch out for that $killer, $name!"] Config.Congratulations = []; // Example: ["Congrats on level $level, $name!"] Config.ShitList = false; // Blacklist hostile players so they don't get invited to party. + Config.UnpartyShitlisted = false; // Leave party if someone invited a blacklisted player. // General config + Config.AutoMap = false; // Set to true to open automap at the beginning of the game. Config.LastMessage = ""; // Message or array of messages to say at the end of the run. Use $nextgame to say next game - "Next game: $nextgame" (works with lead entry point) Config.MinGameTime = 60; // Min game time in seconds. Bot will TP to town and stay in game if the run is completed before. Config.MaxGameTime = 0; // Maximum game time in seconds. Quit game when limit is reached. Config.TeleSwitch = false; // Switch to slot II when teleporting more than 1 node. Config.OpenChests = false; // Open chests. Controls key buying. Config.MiniShopBot = true; // Scan items in NPC shops. - Config.PacketShopping = false; // Use packets to shop. Imporves shopping speed. + Config.PacketShopping = false; // Use packets to shop. Improves shopping speed. Config.TownCheck = false; // Go to town if out of potions Config.LogExperience = false; // Print experience statistics in the manager. Config.PingQuit = [{Ping: 0, Duration: 0}]; // Quit if ping is over the given value for over the given time period in seconds. @@ -392,6 +413,7 @@ function LoadConfig() { Config.FBR = 0; // 0 - disable, 1 to 255 - set value of faster block recovery Config.IAS = 0; // 0 - disable, 1 to 255 - set value of increased attack speed Config.PacketCasting = 0; // 0 = disable, 1 = packet teleport, 2 = full packet casting. + Config.WaypointMenu = false; // Set to true for Single and private realms // Anti-hostile config Config.AntiHostile = false; // Enable anti-hostile @@ -404,6 +426,7 @@ function LoadConfig() { Config.StopOnDClone = true; // Go to town and idle as soon as Diablo walks the Earth Config.SoJWaitTime = 5; // Time in minutes to wait for another SoJ sale before leaving game. 0 = disabled Config.KillDclone = false; // Go to Palace Cellar 3 and try to kill Diablo Clone. Pointless if you already have Annihilus. + Config.DCloneQuit = false; // 1 = quit when Diablo walks, 2 = quit on soj sales, 0 = disabled // Monster skip config // Skip immune monsters. Possible options: "fire", "cold", "lightning", "poison", "physical", "magic". @@ -431,6 +454,14 @@ function LoadConfig() { Config.LowManaSkill[0] = -1; // Timed low mana skill. Config.LowManaSkill[1] = -1; // Untimed low mana skill. + /* Advanced Attack config. Allows custom skills to be used on custom monsters. + * Format: "Monster Name": [timed skill id, untimed skill id] + * Multiple entries are separated by commas + */ + Config.CustomAttack = { + //"Monster Name": [-1, -1] + }; + Config.BossPriority = false; // Set to true to attack Unique/SuperUnique monsters first when clearing Config.ClearType = 0xF; // Monster spectype to kill in level clear scripts (ie. Mausoleum). 0xF = skip normal, 0x7 = champions/bosses, 0 = all Config.TeleStomp = false; // Use merc to attack bosses if they're immune to attacks, but not to physical damage diff --git a/d2bs/kolbot/libs/config/Necromancer.js b/d2bs/kolbot/libs/config/Necromancer.js index c7bd010f0..5e15e1dba 100644 --- a/d2bs/kolbot/libs/config/Necromancer.js +++ b/d2bs/kolbot/libs/config/Necromancer.js @@ -86,6 +86,7 @@ function LoadConfig() { Config.Diablo.EntranceTP = "Entrance TP up"; Config.Diablo.StarTP = "Star TP up"; Config.Diablo.DiabloMsg = "Diablo"; + Scripts.SealLeader = false; // Clear a safe spot around seals and invite leechers in. Leechers should run SealLeecher script. Don't run with Diablo or FastDiablo. // *** act 5 *** Scripts.Pindleskin = false; @@ -124,15 +125,19 @@ function LoadConfig() { Config.Leader = ""; // Leader's ingame character name. Leave blank to try auto-detection (works in AutoBaal, Wakka, MFHelper) Config.QuitList = [""]; // List of character names to quit with. Example: Config.QuitList = ["MySorc", "MyDin"]; + Config.QuitListMode = 0; // 0 = use character names; 1 = use profile names (all profiles must run on the same computer). Scripts.TristramLeech = false; // Enters Tristram, attempts to stay close to the leader and will try and help kill. Scripts.TravincalLeech = false; // Enters portal at back of Travincal. Config.TravincalLeech.Helper = true; // If set to true the character will teleport to the stairs and help attack. Scripts.MFHelper = false; // Run the same MF run as the MFLeader. Leader must have Config.MFLeader = true - Scripts.Wakka = false; // Walking chaos leecher with auto leader assignment, stays at safe distance from the leeader + Scripts.Wakka = false; // Walking chaos leecher with auto leader assignment, stays at safe distance from the leader + Scripts.SealLeecher = false; // Enter safe portals to Chaos. Leader should run SealLeader. Scripts.DiabloHelper = false; // Chaos helper, kills monsters and doesn't open seals on its own. - Config.DiabloHelper.Wait = 120; // Seconds to wait for a runner to be in Chaos - Config.DiabloHelper.Entrance = true; // Start from entrance + Config.DiabloHelper.Wait = 120; // Seconds to wait for a runner to be in Chaos. If Config.Leader is set, it will wait only for the leader. + Config.DiabloHelper.Entrance = true; // Start from entrance. Set to false to start from star. + Config.DiabloHelper.SkipTP = false; // Don't wait for town portal and directly head to chaos. It will clear monsters around chaos entrance and wait for the runner. + Config.DiabloHelper.SkipIfBaal = false; // End script if there are party members in a Baal run. Scripts.AutoBaal = false; // Baal leecher with auto leader assignment Config.AutoBaal.FindShrine = false; // false = disabled, 1 = search after hot tp message, 2 = search as soon as leader is found Config.AutoBaal.LeechSpot = [15115, 5050]; // X, Y coords of Throne Room leech spot @@ -155,14 +160,21 @@ function LoadConfig() { Config.OrgTorch.WaitTimeout = 15; // Time in minutes to wait for keys before moving on Config.OrgTorch.UseSalvation = true; // Use Salvation aura on Mephisto (if possible) Config.OrgTorch.GetFade = false; // Get fade by standing in a fire. You MUST have Last Wish or Treachery on your character being worn. - Scripts.Rusher = false; // Rush bot alpha version (no questing yet, only rushing), for a list of commands, see Rusher.js + Scripts.Rusher = false; // Rush bot. For a list of commands, see Rusher.js Config.Rusher.WaitPlayerCount = 0; // Wait until game has a certain number of players (0 - don't wait, 8 - wait for full game). - Scripts.Rushee = false; // Automatic rushee, works with Rusher + Config.Rusher.Radament = false; // Do Radament quest. + Config.Rusher.LamEsen = false; // Do Lam Esen quest. + Config.Rusher.Izual = false; // Do Izual quest. + Config.Rusher.Shenk = false; // Do Shenk quest. + Config.Rusher.Anya = false; // Do Anya quest. + Config.Rusher.LastRun = ""; // End rush after this run. List of runs: http://pastebin.com/Uez3nZ6g + Scripts.Rushee = false; // Automatic rushee, works with Rusher. Set Rusher's character name as Config.Leader Config.Rushee.Quester = false; // Enter portals and get quest items. Config.Rushee.Bumper = false; // Do Ancients and Baal. Minimum levels: 20 - norm, 40 - nightmare Scripts.CrushTele = false; // classic rush teleporter. go to area of interest and press "-" numpad key Scripts.Questing = false; // solves missing quests (skill/stat+shenk) Scripts.Gamble = false; // Gambling system, other characters will mule gold into your game so you can gamble infinitely. See Gambling.js + Scripts.Crafting = false; // Crafting system, other characters will mule crafting ingredients. See CraftingSystem.js Scripts.GhostBusters = false; // Kill ghosts in most areas that contain them Scripts.Enchant = false; Config.Enchant.Triggers = ["chant", "cows", "wps"]; // Chat commands for enchant, cow level and waypoint giving @@ -173,17 +185,21 @@ function LoadConfig() { Config.IPHunter.IPList = []; // List of IPs to look for. example: [165, 201, 64] Config.IPHunter.GameLength = 3; // Number of minutes to stay in game if ip wasn't found Scripts.KillDclone = false; // Kill Diablo Clone by using Arcane Sanctuary waypoint. Diablo needs to walk the Earth in the game. - Scripts.ShopBot = false; // Fast waypoint-based shopbot - Config.ShopBot.ShopNPC = "Anya"; // Supported NPCs: Fara, Ormus, Anya, Elzix - // Scan only selected classids for maximum speed. See libs/config/templates/ShopBot.txt - Config.ShopBot.ScanIDs = [187, 188, 194, 195, 326, 327, 338, 373, 397, 443, 449]; - Scripts.ChestMania = false; // Open chests in configured areas + Scripts.ShopBot = false; // Shopbot script. Automatically uses shopbot.nip and ignores other pickits. + // Supported NPCs: Akara, Elzix, Fara, Drognan, Ormus, Asheara, Anya. Multiple NPCs are also supported, example: ["Elzix", "Fara"] + // Use common sense when combining NPCs. Shopping in different acts will probably lead to bugs. + Config.ShopBot.ShopNPC = "Anya"; + // Put item classid numbers or names to scan (remember to put quotes around names). Leave blank to scan ALL items. See libs/config/templates/ShopBot.txt + Config.ShopBot.ScanIDs = []; + Config.ShopBot.CycleDelay = 0; // Delay between shopping cycles in milliseconds, might help with crashes. + Config.ShopBot.QuitOnMatch = false; // Leave game as soon as an item is shopped. + Scripts.ChestMania = false; // Open chests in configured areas. See sdk/areas.txt Config.ChestMania.Act1 = [13, 14, 15, 16, 18, 19]; // List of act 1 areas to open chests in Config.ChestMania.Act2 = [55, 59, 65, 66, 67, 68, 69, 70, 71, 72]; // List of act 2 areas to open chests in Config.ChestMania.Act3 = [79, 80, 81, 92, 93, 84, 85, 90]; // List of act 3 areas to open chests in Config.ChestMania.Act4 = []; // List of act 4 areas to open chests in Config.ChestMania.Act5 = [115, 116, 119, 125, 126, 127]; // List of act 5 areas to open chests in - Scripts.ClearAnyArea = false; // Clear any area + Scripts.ClearAnyArea = false; // Clear any area. Uses Config.ClearType to determine which type of monsters to kill. Config.ClearAnyArea.AreaList = []; // List of area ids to clear. See sdk/areas.txt // *** Guest scripts *** @@ -269,13 +285,15 @@ function LoadConfig() { // Additional item info log settings. All info goes to \logs\ItemLog.txt Config.ItemInfo = false; // Log stashed, skipped (due to no space) or sold items. - Config.ItemInfoQuality = []; // The quality of sold items to log. + Config.ItemInfoQuality = []; // The quality of sold items to log. See NTItemAlias.dbl for values. Example: Config.ItemInfoQuality = [6, 7, 8]; // Item identification settings Config.CainID.Enable = false; // Identify items at Cain Config.CainID.MinGold = 2500000; // Minimum gold (stash + character) to have in order to use Cain. Config.CainID.MinUnids = 3; // Minimum number of unid items in order to use Cain. Config.FieldID = false; // Identify items in the field instead of going to town. + Config.DroppedItemsAnnounce.Enable = false; // Announce Dropped Items to in-game newbs + Config.DroppedItemsAnnounce.Quality = []; // Quality of item to announce. See NTItemAlias.dbl for values. Example: Config.DroppedItemsAnnounce.Quality = [6, 7, 8]; // Repair settings Config.CubeRepair = false; // Repair weapons with Ort and armor with Ral rune. Don't use it if you don't understand the risk of losing items. @@ -286,73 +304,73 @@ function LoadConfig() { Config.GambleGoldStart = 1000000; Config.GambleGoldStop = 500000; - // Check libs/NTItemAlias.dbl file for other item classids - Config.GambleItems.push(520); // Amulet - Config.GambleItems.push(522); // Ring - Config.GambleItems.push(418); // Circlet - Config.GambleItems.push(419); // Coronet + // List of item names or classids for gambling. Check libs/NTItemAlias.dbl file for other item classids. + Config.GambleItems.push("Amulet"); + Config.GambleItems.push("Ring"); + Config.GambleItems.push("Circlet"); + Config.GambleItems.push("Coronet"); - /* Cubing config. All recipe names are available in Templates/Cubing.txt - * The format is Config.Recipes.push([recipe_name, item_id, etherealness]). Etherealness is optional and only applies to some recipes. + /* Cubing config. All recipe names are available in Templates/Cubing.txt. For item names/classids check NTItemAlias.dbl + * The format is Config.Recipes.push([recipe_name, item_name_or_classid, etherealness]). Etherealness is optional and only applies to some recipes. */ Config.Cubing = false; // Set to true to enable cubing. // Ingredients for the following recipes will be auto-picked, for classids check libs/NTItemAlias.dbl - //Config.Recipes.push([Recipe.Gem, 560]); // perfect amethyst - //Config.Recipes.push([Recipe.Gem, 565]); // perfect topaz - //Config.Recipes.push([Recipe.Gem, 570]); // perfect sapphire - //Config.Recipes.push([Recipe.Gem, 575]); // perfect emerald - //Config.Recipes.push([Recipe.Gem, 580]); // perfect ruby - //Config.Recipes.push([Recipe.Gem, 585]); // perfect diamond - //Config.Recipes.push([Recipe.Gem, 600]); // perfect skull + //Config.Recipes.push([Recipe.Gem, "Flawless Amethyst"]); // Make Perfect Amethyst + //Config.Recipes.push([Recipe.Gem, "Flawless Topaz"]); // Make Perfect Topaz + //Config.Recipes.push([Recipe.Gem, "Flawless Sapphire"]); // Make Perfect Sapphire + //Config.Recipes.push([Recipe.Gem, "Flawless Emerald"]); // Make Perfect Emerald + //Config.Recipes.push([Recipe.Gem, "Flawless Ruby"]); // Make Perfect Ruby + //Config.Recipes.push([Recipe.Gem, "Flawless Diamond"]); // Make Perfect Diamond + //Config.Recipes.push([Recipe.Gem, "Flawless Skull"]); // Make Perfect Skull - //Config.Recipes.push([Recipe.Token]); // token of absolution - - //Config.Recipes.push([Recipe.Rune, 630]); // pul -> um - //Config.Recipes.push([Recipe.Rune, 631]); // um -> mal - //Config.Recipes.push([Recipe.Rune, 632]); // mal -> ist - //Config.Recipes.push([Recipe.Rune, 633]); // ist -> gul - //Config.Recipes.push([Recipe.Rune, 634]); // gul -> vex + //Config.Recipes.push([Recipe.Token]); // Make Token of Absolution + + //Config.Recipes.push([Recipe.Rune, "Pul Rune"]); // Upgrade Pul to Um + //Config.Recipes.push([Recipe.Rune, "Um Rune"]); // Upgrade Um to Mal + //Config.Recipes.push([Recipe.Rune, "Mal Rune"]); // Upgrade Mal to Ist + //Config.Recipes.push([Recipe.Rune, "Ist Rune"]); // Upgrade Ist to Gul + //Config.Recipes.push([Recipe.Rune, "Gul Rune"]); // Upgrade Gul to Vex //Config.Recipes.push([Recipe.Caster.Amulet]); // Craft Caster Amulet //Config.Recipes.push([Recipe.Blood.Ring]); // Craft Blood Ring - //Config.Recipes.push([Recipe.Blood.Helm, 424]); // Craft Blood Armet - //Config.Recipes.push([Recipe.HitPower.Gloves, 452]); // Craft Hit Power Vambraces + //Config.Recipes.push([Recipe.Blood.Helm, "Armet"]); // Craft Blood Armet + //Config.Recipes.push([Recipe.HitPower.Gloves, "Vambraces"]); // Craft Hit Power Vambraces // The gems not used by other recipes will be used for magic item rerolling. - //Config.Recipes.push([Recipe.Reroll.Magic, 421]); // Reroll magic Diadem - //Config.Recipes.push([Recipe.Reroll.Magic, 605]); // Reroll magic Grand Charm (ilvl 91+) + //Config.Recipes.push([Recipe.Reroll.Magic, "Diadem"]); // Reroll magic Diadem + //Config.Recipes.push([Recipe.Reroll.Magic, "Grand Charm"]); // Reroll magic Grand Charm (ilvl 91+) - //Config.Recipes.push([Recipe.Reroll.Rare, 421]); // Reroll rare Diadem + //Config.Recipes.push([Recipe.Reroll.Rare, "Diadem"]); // Reroll rare Diadem /* Base item for the following recipes must be in pickit. The rest of the ingredients will be auto-picked. * Use Roll.Eth, Roll.NonEth or Roll.All to determine what kind of base item to roll - ethereal, non-ethereal or all. */ - //Config.Recipes.push([Recipe.Socket.Weapon, 255, Roll.Eth]); // Socket ethereal Thresher - //Config.Recipes.push([Recipe.Socket.Weapon, 256, Roll.Eth]); // Socket ethereal Cryptic Axe - //Config.Recipes.push([Recipe.Socket.Armor, 442, Roll.Eth]); // Socket ethereal Sacred Armor - //Config.Recipes.push([Recipe.Socket.Armor, 443, Roll.Eth]); // Socket ethereal Archon Plate + //Config.Recipes.push([Recipe.Socket.Weapon, "Thresher", Roll.Eth]); // Socket ethereal Thresher + //Config.Recipes.push([Recipe.Socket.Weapon, "Cryptic Axe", Roll.Eth]); // Socket ethereal Cryptic Axe + //Config.Recipes.push([Recipe.Socket.Armor, "Sacred Armor", Roll.Eth]); // Socket ethereal Sacred Armor + //Config.Recipes.push([Recipe.Socket.Armor, "Archon Plate", Roll.Eth]); // Socket ethereal Archon Plate - //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, 335, Roll.NonEth]); // Upgrade Bloodfist to Exceptional - //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, 337, Roll.NonEth]); // Upgrade Magefist to Exceptional - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 381, Roll.NonEth]); // Upgrade Bloodfist or Grave Palm to Elite - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 383, Roll.NonEth]); // Upgrade Magefist or Lavagout to Elite - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 389, Roll.NonEth]); // Upgrade Gore Rider to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, "Heavy Gloves", Roll.NonEth]); // Upgrade Bloodfist to Exceptional + //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, "Light Gauntlets", Roll.NonEth]); // Upgrade Magefist to Exceptional + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "Sharkskin Gloves", Roll.NonEth]); // Upgrade Bloodfist or Grave Palm to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "Battle Gauntlets", Roll.NonEth]); // Upgrade Magefist or Lavagout to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "War Boots", Roll.NonEth]); // Upgrade Gore Rider to Elite /* Runeword config. All recipes are available in Templates/Runewords.txt * Keep lines follow pickit format and any given runeword is tested vs ALL lines so you don't need to repeat them */ Config.MakeRunewords = false; // Set to true to enable runeword making/rerolling - //Config.Runewords.push([Runeword.Insight, 255]); // Thresher - //Config.Runewords.push([Runeword.Insight, 256]); // Cryptic Axe + //Config.Runewords.push([Runeword.Insight, "Thresher"]); // Make Insight Thresher + //Config.Runewords.push([Runeword.Insight, "Cryptic Axe"]); // Make Insight Cryptic Axe //Config.KeepRunewords.push("[type] == polearm # [meditationaura] == 17"); - //Config.Runewords.push([Runeword.Spirit, 447]); // Monarch - //Config.Runewords.push([Runeword.Spirit, 498]); // Sacred Targe + //Config.Runewords.push([Runeword.Spirit, "Monarch"]); // Make Spirit Monarch + //Config.Runewords.push([Runeword.Spirit, "Sacred Targe"]); // Make Spirit Sacred Targe //Config.KeepRunewords.push("[type] == shield || [type] == auricshields # [fcr] == 35"); @@ -366,15 +384,17 @@ function LoadConfig() { Config.DeathMessages = []; // Example: ["Watch out for that $killer, $name!"] Config.Congratulations = []; // Example: ["Congrats on level $level, $name!"] Config.ShitList = false; // Blacklist hostile players so they don't get invited to party. + Config.UnpartyShitlisted = false; // Leave party if someone invited a blacklisted player. // General config + Config.AutoMap = false; // Set to true to open automap at the beginning of the game. Config.LastMessage = ""; // Message or array of messages to say at the end of the run. Use $nextgame to say next game - "Next game: $nextgame" (works with lead entry point) Config.MinGameTime = 60; // Min game time in seconds. Bot will TP to town and stay in game if the run is completed before. Config.MaxGameTime = 0; // Maximum game time in seconds. Quit game when limit is reached. Config.TeleSwitch = false; // Switch to slot II when teleporting more than 1 node. Config.OpenChests = false; // Open chests. Controls key buying. Config.MiniShopBot = true; // Scan items in NPC shops. - Config.PacketShopping = false; // Use packets to shop. Imporves shopping speed. + Config.PacketShopping = false; // Use packets to shop. Improves shopping speed. Config.TownCheck = false; // Go to town if out of potions Config.LogExperience = false; // Print experience statistics in the manager. Config.PingQuit = [{Ping: 0, Duration: 0}]; // Quit if ping is over the given value for over the given time period in seconds. @@ -393,6 +413,7 @@ function LoadConfig() { Config.FBR = 0; // 0 - disable, 1 to 255 - set value of faster block recovery Config.IAS = 0; // 0 - disable, 1 to 255 - set value of increased attack speed Config.PacketCasting = 0; // 0 = disable, 1 = packet teleport, 2 = full packet casting. + Config.WaypointMenu = false; // Set to true for Single and private realms // Anti-hostile config Config.AntiHostile = false; // Enable anti-hostile @@ -405,6 +426,7 @@ function LoadConfig() { Config.StopOnDClone = true; // Go to town and idle as soon as Diablo walks the Earth Config.SoJWaitTime = 5; // Time in minutes to wait for another SoJ sale before leaving game. 0 = disabled Config.KillDclone = false; // Go to Palace Cellar 3 and try to kill Diablo Clone. Pointless if you already have Annihilus. + Config.DCloneQuit = false; // 1 = quit when Diablo walks, 2 = quit on soj sales, 0 = disabled // Monster skip config // Skip immune monsters. Possible options: "fire", "cold", "lightning", "poison", "physical", "magic". @@ -432,6 +454,14 @@ function LoadConfig() { Config.LowManaSkill[0] = -1; // Timed low mana skill. Config.LowManaSkill[1] = -1; // Untimed low mana skill. + /* Advanced Attack config. Allows custom skills to be used on custom monsters. + * Format: "Monster Name": [timed skill id, untimed skill id] + * Multiple entries are separated by commas + */ + Config.CustomAttack = { + //"Monster Name": [-1, -1] + }; + Config.Dodge = false; // Move away from monsters that get too close. Don't use with short-ranged attacks like Poison Dagger. Config.DodgeRange = 15; // Distance to keep from monsters. Config.DodgeHP = 100; // Dodge only if HP percent is less than or equal to Config.DodgeHP. 100 = always dodge. diff --git a/d2bs/kolbot/libs/config/Paladin.js b/d2bs/kolbot/libs/config/Paladin.js index 6d0fb8bab..c201481be 100644 --- a/d2bs/kolbot/libs/config/Paladin.js +++ b/d2bs/kolbot/libs/config/Paladin.js @@ -86,6 +86,7 @@ function LoadConfig() { Config.Diablo.EntranceTP = "Entrance TP up"; Config.Diablo.StarTP = "Star TP up"; Config.Diablo.DiabloMsg = "Diablo"; + Scripts.SealLeader = false; // Clear a safe spot around seals and invite leechers in. Leechers should run SealLeecher script. Don't run with Diablo or FastDiablo. // *** act 5 *** Scripts.Pindleskin = false; @@ -124,15 +125,19 @@ function LoadConfig() { Config.Leader = ""; // Leader's ingame character name. Leave blank to try auto-detection (works in AutoBaal, Wakka, MFHelper) Config.QuitList = [""]; // List of character names to quit with. Example: Config.QuitList = ["MySorc", "MyDin"]; + Config.QuitListMode = 0; // 0 = use character names; 1 = use profile names (all profiles must run on the same computer). Scripts.TristramLeech = false; // Enters Tristram, attempts to stay close to the leader and will try and help kill. Scripts.TravincalLeech = false; // Enters portal at back of Travincal. Config.TravincalLeech.Helper = true; // If set to true the character will teleport to the stairs and help attack. Scripts.MFHelper = false; // Run the same MF run as the MFLeader. Leader must have Config.MFLeader = true - Scripts.Wakka = false; // Walking chaos leecher with auto leader assignment, stays at safe distance from the leeader + Scripts.Wakka = false; // Walking chaos leecher with auto leader assignment, stays at safe distance from the leader + Scripts.SealLeecher = false; // Enter safe portals to Chaos. Leader should run SealLeader. Scripts.DiabloHelper = false; // Chaos helper, kills monsters and doesn't open seals on its own. - Config.DiabloHelper.Wait = 120; // Seconds to wait for a runner to be in Chaos - Config.DiabloHelper.Entrance = true; // Start from entrance + Config.DiabloHelper.Wait = 120; // Seconds to wait for a runner to be in Chaos. If Config.Leader is set, it will wait only for the leader. + Config.DiabloHelper.Entrance = true; // Start from entrance. Set to false to start from star. + Config.DiabloHelper.SkipTP = false; // Don't wait for town portal and directly head to chaos. It will clear monsters around chaos entrance and wait for the runner. + Config.DiabloHelper.SkipIfBaal = false; // End script if there are party members in a Baal run. Scripts.AutoBaal = false; // Baal leecher with auto leader assignment Config.AutoBaal.FindShrine = false; // false = disabled, 1 = search after hot tp message, 2 = search as soon as leader is found Config.AutoBaal.LeechSpot = [15115, 5050]; // X, Y coords of Throne Room leech spot @@ -155,14 +160,21 @@ function LoadConfig() { Config.OrgTorch.WaitTimeout = 15; // Time in minutes to wait for keys before moving on Config.OrgTorch.UseSalvation = true; // Use Salvation aura on Mephisto (if possible) Config.OrgTorch.GetFade = false; // Get fade by standing in a fire. You MUST have Last Wish or Treachery on your character being worn. - Scripts.Rusher = false; // Rush bot alpha version (no questing yet, only rushing), for a list of commands, see Rusher.js + Scripts.Rusher = false; // Rush bot. For a list of commands, see Rusher.js Config.Rusher.WaitPlayerCount = 0; // Wait until game has a certain number of players (0 - don't wait, 8 - wait for full game). - Scripts.Rushee = false; // Automatic rushee, works with Rusher + Config.Rusher.Radament = false; // Do Radament quest. + Config.Rusher.LamEsen = false; // Do Lam Esen quest. + Config.Rusher.Izual = false; // Do Izual quest. + Config.Rusher.Shenk = false; // Do Shenk quest. + Config.Rusher.Anya = false; // Do Anya quest. + Config.Rusher.LastRun = ""; // End rush after this run. List of runs: http://pastebin.com/Uez3nZ6g + Scripts.Rushee = false; // Automatic rushee, works with Rusher. Set Rusher's character name as Config.Leader Config.Rushee.Quester = false; // Enter portals and get quest items. Config.Rushee.Bumper = false; // Do Ancients and Baal. Minimum levels: 20 - norm, 40 - nightmare Scripts.CrushTele = false; // classic rush teleporter. go to area of interest and press "-" numpad key Scripts.Questing = false; // solves missing quests (skill/stat+shenk) Scripts.Gamble = false; // Gambling system, other characters will mule gold into your game so you can gamble infinitely. See Gambling.js + Scripts.Crafting = false; // Crafting system, other characters will mule crafting ingredients. See CraftingSystem.js Scripts.GhostBusters = false; // Kill ghosts in most areas that contain them Scripts.Enchant = false; Config.Enchant.Triggers = ["chant", "cows", "wps"]; // Chat commands for enchant, cow level and waypoint giving @@ -173,17 +185,21 @@ function LoadConfig() { Config.IPHunter.IPList = []; // List of IPs to look for. example: [165, 201, 64] Config.IPHunter.GameLength = 3; // Number of minutes to stay in game if ip wasn't found Scripts.KillDclone = false; // Kill Diablo Clone by using Arcane Sanctuary waypoint. Diablo needs to walk the Earth in the game. - Scripts.ShopBot = false; // Fast waypoint-based shopbot - Config.ShopBot.ShopNPC = "Anya"; // Supported NPCs: Fara, Ormus, Anya, Elzix - // Scan only selected classids for maximum speed. See libs/config/templates/ShopBot.txt - Config.ShopBot.ScanIDs = [187, 188, 194, 195, 326, 327, 338, 373, 397, 443, 449]; - Scripts.ChestMania = false; // Open chests in configured areas + Scripts.ShopBot = false; // Shopbot script. Automatically uses shopbot.nip and ignores other pickits. + // Supported NPCs: Akara, Elzix, Fara, Drognan, Ormus, Asheara, Anya. Multiple NPCs are also supported, example: ["Elzix", "Fara"] + // Use common sense when combining NPCs. Shopping in different acts will probably lead to bugs. + Config.ShopBot.ShopNPC = "Anya"; + // Put item classid numbers or names to scan (remember to put quotes around names). Leave blank to scan ALL items. See libs/config/templates/ShopBot.txt + Config.ShopBot.ScanIDs = []; + Config.ShopBot.CycleDelay = 0; // Delay between shopping cycles in milliseconds, might help with crashes. + Config.ShopBot.QuitOnMatch = false; // Leave game as soon as an item is shopped. + Scripts.ChestMania = false; // Open chests in configured areas. See sdk/areas.txt Config.ChestMania.Act1 = [13, 14, 15, 16, 18, 19]; // List of act 1 areas to open chests in Config.ChestMania.Act2 = [55, 59, 65, 66, 67, 68, 69, 70, 71, 72]; // List of act 2 areas to open chests in Config.ChestMania.Act3 = [79, 80, 81, 92, 93, 84, 85, 90]; // List of act 3 areas to open chests in Config.ChestMania.Act4 = []; // List of act 4 areas to open chests in Config.ChestMania.Act5 = [115, 116, 119, 125, 126, 127]; // List of act 5 areas to open chests in - Scripts.ClearAnyArea = false; // Clear any area + Scripts.ClearAnyArea = false; // Clear any area. Uses Config.ClearType to determine which type of monsters to kill. Config.ClearAnyArea.AreaList = []; // List of area ids to clear. See sdk/areas.txt // *** Guest scripts *** @@ -269,13 +285,15 @@ function LoadConfig() { // Additional item info log settings. All info goes to \logs\ItemLog.txt Config.ItemInfo = false; // Log stashed, skipped (due to no space) or sold items. - Config.ItemInfoQuality = []; // The quality of sold items to log. + Config.ItemInfoQuality = []; // The quality of sold items to log. See NTItemAlias.dbl for values. Example: Config.ItemInfoQuality = [6, 7, 8]; // Item identification settings Config.CainID.Enable = false; // Identify items at Cain Config.CainID.MinGold = 2500000; // Minimum gold (stash + character) to have in order to use Cain. Config.CainID.MinUnids = 3; // Minimum number of unid items in order to use Cain. Config.FieldID = false; // Identify items in the field instead of going to town. + Config.DroppedItemsAnnounce.Enable = false; // Announce Dropped Items to in-game newbs + Config.DroppedItemsAnnounce.Quality = []; // Quality of item to announce. See NTItemAlias.dbl for values. Example: Config.DroppedItemsAnnounce.Quality = [6, 7, 8]; // Repair settings Config.CubeRepair = false; // Repair weapons with Ort and armor with Ral rune. Don't use it if you don't understand the risk of losing items. @@ -286,73 +304,73 @@ function LoadConfig() { Config.GambleGoldStart = 1000000; Config.GambleGoldStop = 500000; - // Check libs/NTItemAlias.dbl file for other item classids - Config.GambleItems.push(520); // Amulet - Config.GambleItems.push(522); // Ring - Config.GambleItems.push(418); // Circlet - Config.GambleItems.push(419); // Coronet + // List of item names or classids for gambling. Check libs/NTItemAlias.dbl file for other item classids. + Config.GambleItems.push("Amulet"); + Config.GambleItems.push("Ring"); + Config.GambleItems.push("Circlet"); + Config.GambleItems.push("Coronet"); - /* Cubing config. All recipe names are available in Templates/Cubing.txt - * The format is Config.Recipes.push([recipe_name, item_id, etherealness]). Etherealness is optional and only applies to some recipes. + /* Cubing config. All recipe names are available in Templates/Cubing.txt. For item names/classids check NTItemAlias.dbl + * The format is Config.Recipes.push([recipe_name, item_name_or_classid, etherealness]). Etherealness is optional and only applies to some recipes. */ Config.Cubing = false; // Set to true to enable cubing. // Ingredients for the following recipes will be auto-picked, for classids check libs/NTItemAlias.dbl - //Config.Recipes.push([Recipe.Gem, 560]); // perfect amethyst - //Config.Recipes.push([Recipe.Gem, 565]); // perfect topaz - //Config.Recipes.push([Recipe.Gem, 570]); // perfect sapphire - //Config.Recipes.push([Recipe.Gem, 575]); // perfect emerald - //Config.Recipes.push([Recipe.Gem, 580]); // perfect ruby - //Config.Recipes.push([Recipe.Gem, 585]); // perfect diamond - //Config.Recipes.push([Recipe.Gem, 600]); // perfect skull + //Config.Recipes.push([Recipe.Gem, "Flawless Amethyst"]); // Make Perfect Amethyst + //Config.Recipes.push([Recipe.Gem, "Flawless Topaz"]); // Make Perfect Topaz + //Config.Recipes.push([Recipe.Gem, "Flawless Sapphire"]); // Make Perfect Sapphire + //Config.Recipes.push([Recipe.Gem, "Flawless Emerald"]); // Make Perfect Emerald + //Config.Recipes.push([Recipe.Gem, "Flawless Ruby"]); // Make Perfect Ruby + //Config.Recipes.push([Recipe.Gem, "Flawless Diamond"]); // Make Perfect Diamond + //Config.Recipes.push([Recipe.Gem, "Flawless Skull"]); // Make Perfect Skull - //Config.Recipes.push([Recipe.Token]); // token of absolution - - //Config.Recipes.push([Recipe.Rune, 630]); // pul -> um - //Config.Recipes.push([Recipe.Rune, 631]); // um -> mal - //Config.Recipes.push([Recipe.Rune, 632]); // mal -> ist - //Config.Recipes.push([Recipe.Rune, 633]); // ist -> gul - //Config.Recipes.push([Recipe.Rune, 634]); // gul -> vex + //Config.Recipes.push([Recipe.Token]); // Make Token of Absolution + + //Config.Recipes.push([Recipe.Rune, "Pul Rune"]); // Upgrade Pul to Um + //Config.Recipes.push([Recipe.Rune, "Um Rune"]); // Upgrade Um to Mal + //Config.Recipes.push([Recipe.Rune, "Mal Rune"]); // Upgrade Mal to Ist + //Config.Recipes.push([Recipe.Rune, "Ist Rune"]); // Upgrade Ist to Gul + //Config.Recipes.push([Recipe.Rune, "Gul Rune"]); // Upgrade Gul to Vex //Config.Recipes.push([Recipe.Caster.Amulet]); // Craft Caster Amulet //Config.Recipes.push([Recipe.Blood.Ring]); // Craft Blood Ring - //Config.Recipes.push([Recipe.Blood.Helm, 424]); // Craft Blood Armet - //Config.Recipes.push([Recipe.HitPower.Gloves, 452]); // Craft Hit Power Vambraces + //Config.Recipes.push([Recipe.Blood.Helm, "Armet"]); // Craft Blood Armet + //Config.Recipes.push([Recipe.HitPower.Gloves, "Vambraces"]); // Craft Hit Power Vambraces // The gems not used by other recipes will be used for magic item rerolling. - //Config.Recipes.push([Recipe.Reroll.Magic, 421]); // Reroll magic Diadem - //Config.Recipes.push([Recipe.Reroll.Magic, 605]); // Reroll magic Grand Charm (ilvl 91+) + //Config.Recipes.push([Recipe.Reroll.Magic, "Diadem"]); // Reroll magic Diadem + //Config.Recipes.push([Recipe.Reroll.Magic, "Grand Charm"]); // Reroll magic Grand Charm (ilvl 91+) - //Config.Recipes.push([Recipe.Reroll.Rare, 421]); // Reroll rare Diadem + //Config.Recipes.push([Recipe.Reroll.Rare, "Diadem"]); // Reroll rare Diadem /* Base item for the following recipes must be in pickit. The rest of the ingredients will be auto-picked. * Use Roll.Eth, Roll.NonEth or Roll.All to determine what kind of base item to roll - ethereal, non-ethereal or all. */ - //Config.Recipes.push([Recipe.Socket.Weapon, 255, Roll.Eth]); // Socket ethereal Thresher - //Config.Recipes.push([Recipe.Socket.Weapon, 256, Roll.Eth]); // Socket ethereal Cryptic Axe - //Config.Recipes.push([Recipe.Socket.Armor, 442, Roll.Eth]); // Socket ethereal Sacred Armor - //Config.Recipes.push([Recipe.Socket.Armor, 443, Roll.Eth]); // Socket ethereal Archon Plate + //Config.Recipes.push([Recipe.Socket.Weapon, "Thresher", Roll.Eth]); // Socket ethereal Thresher + //Config.Recipes.push([Recipe.Socket.Weapon, "Cryptic Axe", Roll.Eth]); // Socket ethereal Cryptic Axe + //Config.Recipes.push([Recipe.Socket.Armor, "Sacred Armor", Roll.Eth]); // Socket ethereal Sacred Armor + //Config.Recipes.push([Recipe.Socket.Armor, "Archon Plate", Roll.Eth]); // Socket ethereal Archon Plate - //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, 335, Roll.NonEth]); // Upgrade Bloodfist to Exceptional - //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, 337, Roll.NonEth]); // Upgrade Magefist to Exceptional - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 381, Roll.NonEth]); // Upgrade Bloodfist or Grave Palm to Elite - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 383, Roll.NonEth]); // Upgrade Magefist or Lavagout to Elite - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 389, Roll.NonEth]); // Upgrade Gore Rider to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, "Heavy Gloves", Roll.NonEth]); // Upgrade Bloodfist to Exceptional + //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, "Light Gauntlets", Roll.NonEth]); // Upgrade Magefist to Exceptional + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "Sharkskin Gloves", Roll.NonEth]); // Upgrade Bloodfist or Grave Palm to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "Battle Gauntlets", Roll.NonEth]); // Upgrade Magefist or Lavagout to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "War Boots", Roll.NonEth]); // Upgrade Gore Rider to Elite /* Runeword config. All recipes are available in Templates/Runewords.txt * Keep lines follow pickit format and any given runeword is tested vs ALL lines so you don't need to repeat them */ Config.MakeRunewords = false; // Set to true to enable runeword making/rerolling - //Config.Runewords.push([Runeword.Insight, 255]); // Thresher - //Config.Runewords.push([Runeword.Insight, 256]); // Cryptic Axe + //Config.Runewords.push([Runeword.Insight, "Thresher"]); // Make Insight Thresher + //Config.Runewords.push([Runeword.Insight, "Cryptic Axe"]); // Make Insight Cryptic Axe //Config.KeepRunewords.push("[type] == polearm # [meditationaura] == 17"); - //Config.Runewords.push([Runeword.Spirit, 447]); // Monarch - //Config.Runewords.push([Runeword.Spirit, 498]); // Sacred Targe + //Config.Runewords.push([Runeword.Spirit, "Monarch"]); // Make Spirit Monarch + //Config.Runewords.push([Runeword.Spirit, "Sacred Targe"]); // Make Spirit Sacred Targe //Config.KeepRunewords.push("[type] == shield || [type] == auricshields # [fcr] == 35"); @@ -366,15 +384,17 @@ function LoadConfig() { Config.DeathMessages = []; // Example: ["Watch out for that $killer, $name!"] Config.Congratulations = []; // Example: ["Congrats on level $level, $name!"] Config.ShitList = false; // Blacklist hostile players so they don't get invited to party. + Config.UnpartyShitlisted = false; // Leave party if someone invited a blacklisted player. // General config + Config.AutoMap = false; // Set to true to open automap at the beginning of the game. Config.LastMessage = ""; // Message or array of messages to say at the end of the run. Use $nextgame to say next game - "Next game: $nextgame" (works with lead entry point) Config.MinGameTime = 60; // Min game time in seconds. Bot will TP to town and stay in game if the run is completed before. Config.MaxGameTime = 0; // Maximum game time in seconds. Quit game when limit is reached. Config.TeleSwitch = false; // Switch to slot II when teleporting more than 1 node. Config.OpenChests = false; // Open chests. Controls key buying. Config.MiniShopBot = true; // Scan items in NPC shops. - Config.PacketShopping = false; // Use packets to shop. Imporves shopping speed. + Config.PacketShopping = false; // Use packets to shop. Improves shopping speed. Config.TownCheck = false; // Go to town if out of potions Config.LogExperience = false; // Print experience statistics in the manager. Config.PingQuit = [{Ping: 0, Duration: 0}]; // Quit if ping is over the given value for over the given time period in seconds. @@ -393,6 +413,7 @@ function LoadConfig() { Config.FBR = 0; // 0 - disable, 1 to 255 - set value of faster block recovery Config.IAS = 0; // 0 - disable, 1 to 255 - set value of increased attack speed Config.PacketCasting = 0; // 0 = disable, 1 = packet teleport, 2 = full packet casting. + Config.WaypointMenu = false; // Set to true for Single and private realms // Anti-hostile config Config.AntiHostile = false; // Enable anti-hostile @@ -405,6 +426,7 @@ function LoadConfig() { Config.StopOnDClone = true; // Go to town and idle as soon as Diablo walks the Earth Config.SoJWaitTime = 5; // Time in minutes to wait for another SoJ sale before leaving game. 0 = disabled Config.KillDclone = false; // Go to Palace Cellar 3 and try to kill Diablo Clone. Pointless if you already have Annihilus. + Config.DCloneQuit = false; // 1 = quit when Diablo walks, 2 = quit on soj sales, 0 = disabled // Monster skip config // Skip immune monsters. Possible options: "fire", "cold", "lightning", "poison", "physical", "magic". @@ -432,6 +454,14 @@ function LoadConfig() { Config.LowManaSkill[0] = -1; // Low mana skill. Config.LowManaSkill[1] = -1; // Low mana aura. + /* Advanced Attack config. Allows custom skills to be used on custom monsters. + * Format: "Monster Name": [attack skill id, aura skill id] + * Multiple entries are separated by commas + */ + Config.CustomAttack = { + //"Monster Name": [-1, -1] + }; + Config.BossPriority = false; // Set to true to attack Unique/SuperUnique monsters first when clearing Config.ClearType = 0xF; // Monster spectype to kill in level clear scripts (ie. Mausoleum). 0xF = skip normal, 0x7 = champions/bosses, 0 = all @@ -441,6 +471,7 @@ function LoadConfig() { // Class specific config Config.AvoidDolls = false; // Try to attack Soul Killers from a greater distance with hammerdins. Config.Vigor = true; // Swith to Vigor when running + Config.Charge = true; // Use Charge when running Config.Redemption = [50, 50]; // Switch to Redemption after clearing an area if under designated life or mana. Format: [lifepercent, manapercent] diff --git a/d2bs/kolbot/libs/config/Sorceress.js b/d2bs/kolbot/libs/config/Sorceress.js index 8a15ed1da..e3ad28121 100644 --- a/d2bs/kolbot/libs/config/Sorceress.js +++ b/d2bs/kolbot/libs/config/Sorceress.js @@ -86,6 +86,7 @@ function LoadConfig() { Config.Diablo.EntranceTP = "Entrance TP up"; Config.Diablo.StarTP = "Star TP up"; Config.Diablo.DiabloMsg = "Diablo"; + Scripts.SealLeader = false; // Clear a safe spot around seals and invite leechers in. Leechers should run SealLeecher script. Don't run with Diablo or FastDiablo. // *** act 5 *** Scripts.Pindleskin = false; @@ -124,15 +125,19 @@ function LoadConfig() { Config.Leader = ""; // Leader's ingame character name. Leave blank to try auto-detection (works in AutoBaal, Wakka, MFHelper) Config.QuitList = [""]; // List of character names to quit with. Example: Config.QuitList = ["MySorc", "MyDin"]; + Config.QuitListMode = 0; // 0 = use character names; 1 = use profile names (all profiles must run on the same computer). Scripts.TristramLeech = false; // Enters Tristram, attempts to stay close to the leader and will try and help kill. Scripts.TravincalLeech = false; // Enters portal at back of Travincal. Config.TravincalLeech.Helper = true; // If set to true the character will teleport to the stairs and help attack. Scripts.MFHelper = false; // Run the same MF run as the MFLeader. Leader must have Config.MFLeader = true - Scripts.Wakka = false; // Walking chaos leecher with auto leader assignment, stays at safe distance from the leeader + Scripts.Wakka = false; // Walking chaos leecher with auto leader assignment, stays at safe distance from the leader + Scripts.SealLeecher = false; // Enter safe portals to Chaos. Leader should run SealLeader. Scripts.DiabloHelper = false; // Chaos helper, kills monsters and doesn't open seals on its own. - Config.DiabloHelper.Wait = 120; // Seconds to wait for a runner to be in Chaos - Config.DiabloHelper.Entrance = true; // Start from entrance + Config.DiabloHelper.Wait = 120; // Seconds to wait for a runner to be in Chaos. If Config.Leader is set, it will wait only for the leader. + Config.DiabloHelper.Entrance = true; // Start from entrance. Set to false to start from star. + Config.DiabloHelper.SkipTP = false; // Don't wait for town portal and directly head to chaos. It will clear monsters around chaos entrance and wait for the runner. + Config.DiabloHelper.SkipIfBaal = false; // End script if there are party members in a Baal run. Scripts.AutoBaal = false; // Baal leecher with auto leader assignment Config.AutoBaal.FindShrine = false; // false = disabled, 1 = search after hot tp message, 2 = search as soon as leader is found Config.AutoBaal.LeechSpot = [15115, 5050]; // X, Y coords of Throne Room leech spot @@ -155,14 +160,21 @@ function LoadConfig() { Config.OrgTorch.WaitTimeout = 15; // Time in minutes to wait for keys before moving on Config.OrgTorch.UseSalvation = true; // Use Salvation aura on Mephisto (if possible) Config.OrgTorch.GetFade = false; // Get fade by standing in a fire. You MUST have Last Wish or Treachery on your character being worn. - Scripts.Rusher = false; // Rush bot alpha version (no questing yet, only rushing), for a list of commands, see Rusher.js + Scripts.Rusher = false; // Rush bot. For a list of commands, see Rusher.js Config.Rusher.WaitPlayerCount = 0; // Wait until game has a certain number of players (0 - don't wait, 8 - wait for full game). - Scripts.Rushee = false; // Automatic rushee, works with Rusher + Config.Rusher.Radament = false; // Do Radament quest. + Config.Rusher.LamEsen = false; // Do Lam Esen quest. + Config.Rusher.Izual = false; // Do Izual quest. + Config.Rusher.Shenk = false; // Do Shenk quest. + Config.Rusher.Anya = false; // Do Anya quest. + Config.Rusher.LastRun = ""; // End rush after this run. List of runs: http://pastebin.com/Uez3nZ6g + Scripts.Rushee = false; // Automatic rushee, works with Rusher. Set Rusher's character name as Config.Leader Config.Rushee.Quester = false; // Enter portals and get quest items. Config.Rushee.Bumper = false; // Do Ancients and Baal. Minimum levels: 20 - norm, 40 - nightmare Scripts.CrushTele = false; // classic rush teleporter. go to area of interest and press "-" numpad key Scripts.Questing = false; // solves missing quests (skill/stat+shenk) Scripts.Gamble = false; // Gambling system, other characters will mule gold into your game so you can gamble infinitely. See Gambling.js + Scripts.Crafting = false; // Crafting system, other characters will mule crafting ingredients. See CraftingSystem.js Scripts.GhostBusters = false; // Kill ghosts in most areas that contain them Scripts.Enchant = false; Config.Enchant.Triggers = ["chant", "cows", "wps"]; // Chat commands for enchant, cow level and waypoint giving @@ -173,17 +185,21 @@ function LoadConfig() { Config.IPHunter.IPList = []; // List of IPs to look for. example: [165, 201, 64] Config.IPHunter.GameLength = 3; // Number of minutes to stay in game if ip wasn't found Scripts.KillDclone = false; // Kill Diablo Clone by using Arcane Sanctuary waypoint. Diablo needs to walk the Earth in the game. - Scripts.ShopBot = false; // Fast waypoint-based shopbot - Config.ShopBot.ShopNPC = "Anya"; // Supported NPCs: Fara, Ormus, Anya, Elzix - // Scan only selected classids for maximum speed. See libs/config/templates/ShopBot.txt - Config.ShopBot.ScanIDs = [187, 188, 194, 195, 326, 327, 338, 373, 397, 443, 449]; - Scripts.ChestMania = false; // Open chests in configured areas + Scripts.ShopBot = false; // Shopbot script. Automatically uses shopbot.nip and ignores other pickits. + // Supported NPCs: Akara, Elzix, Fara, Drognan, Ormus, Asheara, Anya. Multiple NPCs are also supported, example: ["Elzix", "Fara"] + // Use common sense when combining NPCs. Shopping in different acts will probably lead to bugs. + Config.ShopBot.ShopNPC = "Anya"; + // Put item classid numbers or names to scan (remember to put quotes around names). Leave blank to scan ALL items. See libs/config/templates/ShopBot.txt + Config.ShopBot.ScanIDs = []; + Config.ShopBot.CycleDelay = 0; // Delay between shopping cycles in milliseconds, might help with crashes. + Config.ShopBot.QuitOnMatch = false; // Leave game as soon as an item is shopped. + Scripts.ChestMania = false; // Open chests in configured areas. See sdk/areas.txt Config.ChestMania.Act1 = [13, 14, 15, 16, 18, 19]; // List of act 1 areas to open chests in Config.ChestMania.Act2 = [55, 59, 65, 66, 67, 68, 69, 70, 71, 72]; // List of act 2 areas to open chests in Config.ChestMania.Act3 = [79, 80, 81, 92, 93, 84, 85, 90]; // List of act 3 areas to open chests in Config.ChestMania.Act4 = []; // List of act 4 areas to open chests in Config.ChestMania.Act5 = [115, 116, 119, 125, 126, 127]; // List of act 5 areas to open chests in - Scripts.ClearAnyArea = false; // Clear any area + Scripts.ClearAnyArea = false; // Clear any area. Uses Config.ClearType to determine which type of monsters to kill. Config.ClearAnyArea.AreaList = []; // List of area ids to clear. See sdk/areas.txt // *** Guest scripts *** @@ -269,13 +285,15 @@ function LoadConfig() { // Additional item info log settings. All info goes to \logs\ItemLog.txt Config.ItemInfo = false; // Log stashed, skipped (due to no space) or sold items. - Config.ItemInfoQuality = []; // The quality of sold items to log. + Config.ItemInfoQuality = []; // The quality of sold items to log. See NTItemAlias.dbl for values. Example: Config.ItemInfoQuality = [6, 7, 8]; // Item identification settings Config.CainID.Enable = false; // Identify items at Cain Config.CainID.MinGold = 2500000; // Minimum gold (stash + character) to have in order to use Cain. Config.CainID.MinUnids = 3; // Minimum number of unid items in order to use Cain. Config.FieldID = false; // Identify items in the field instead of going to town. + Config.DroppedItemsAnnounce.Enable = false; // Announce Dropped Items to in-game newbs + Config.DroppedItemsAnnounce.Quality = []; // Quality of item to announce. See NTItemAlias.dbl for values. Example: Config.DroppedItemsAnnounce.Quality = [6, 7, 8]; // Repair settings Config.CubeRepair = false; // Repair weapons with Ort and armor with Ral rune. Don't use it if you don't understand the risk of losing items. @@ -286,73 +304,73 @@ function LoadConfig() { Config.GambleGoldStart = 1000000; Config.GambleGoldStop = 500000; - // Check libs/NTItemAlias.dbl file for other item classids - Config.GambleItems.push(520); // Amulet - Config.GambleItems.push(522); // Ring - Config.GambleItems.push(418); // Circlet - Config.GambleItems.push(419); // Coronet + // List of item names or classids for gambling. Check libs/NTItemAlias.dbl file for other item classids. + Config.GambleItems.push("Amulet"); + Config.GambleItems.push("Ring"); + Config.GambleItems.push("Circlet"); + Config.GambleItems.push("Coronet"); - /* Cubing config. All recipe names are available in Templates/Cubing.txt - * The format is Config.Recipes.push([recipe_name, item_id, etherealness]). Etherealness is optional and only applies to some recipes. + /* Cubing config. All recipe names are available in Templates/Cubing.txt. For item names/classids check NTItemAlias.dbl + * The format is Config.Recipes.push([recipe_name, item_name_or_classid, etherealness]). Etherealness is optional and only applies to some recipes. */ Config.Cubing = false; // Set to true to enable cubing. // Ingredients for the following recipes will be auto-picked, for classids check libs/NTItemAlias.dbl - //Config.Recipes.push([Recipe.Gem, 560]); // perfect amethyst - //Config.Recipes.push([Recipe.Gem, 565]); // perfect topaz - //Config.Recipes.push([Recipe.Gem, 570]); // perfect sapphire - //Config.Recipes.push([Recipe.Gem, 575]); // perfect emerald - //Config.Recipes.push([Recipe.Gem, 580]); // perfect ruby - //Config.Recipes.push([Recipe.Gem, 585]); // perfect diamond - //Config.Recipes.push([Recipe.Gem, 600]); // perfect skull + //Config.Recipes.push([Recipe.Gem, "Flawless Amethyst"]); // Make Perfect Amethyst + //Config.Recipes.push([Recipe.Gem, "Flawless Topaz"]); // Make Perfect Topaz + //Config.Recipes.push([Recipe.Gem, "Flawless Sapphire"]); // Make Perfect Sapphire + //Config.Recipes.push([Recipe.Gem, "Flawless Emerald"]); // Make Perfect Emerald + //Config.Recipes.push([Recipe.Gem, "Flawless Ruby"]); // Make Perfect Ruby + //Config.Recipes.push([Recipe.Gem, "Flawless Diamond"]); // Make Perfect Diamond + //Config.Recipes.push([Recipe.Gem, "Flawless Skull"]); // Make Perfect Skull - //Config.Recipes.push([Recipe.Token]); // token of absolution - - //Config.Recipes.push([Recipe.Rune, 630]); // pul -> um - //Config.Recipes.push([Recipe.Rune, 631]); // um -> mal - //Config.Recipes.push([Recipe.Rune, 632]); // mal -> ist - //Config.Recipes.push([Recipe.Rune, 633]); // ist -> gul - //Config.Recipes.push([Recipe.Rune, 634]); // gul -> vex + //Config.Recipes.push([Recipe.Token]); // Make Token of Absolution + + //Config.Recipes.push([Recipe.Rune, "Pul Rune"]); // Upgrade Pul to Um + //Config.Recipes.push([Recipe.Rune, "Um Rune"]); // Upgrade Um to Mal + //Config.Recipes.push([Recipe.Rune, "Mal Rune"]); // Upgrade Mal to Ist + //Config.Recipes.push([Recipe.Rune, "Ist Rune"]); // Upgrade Ist to Gul + //Config.Recipes.push([Recipe.Rune, "Gul Rune"]); // Upgrade Gul to Vex //Config.Recipes.push([Recipe.Caster.Amulet]); // Craft Caster Amulet //Config.Recipes.push([Recipe.Blood.Ring]); // Craft Blood Ring - //Config.Recipes.push([Recipe.Blood.Helm, 424]); // Craft Blood Armet - //Config.Recipes.push([Recipe.HitPower.Gloves, 452]); // Craft Hit Power Vambraces + //Config.Recipes.push([Recipe.Blood.Helm, "Armet"]); // Craft Blood Armet + //Config.Recipes.push([Recipe.HitPower.Gloves, "Vambraces"]); // Craft Hit Power Vambraces // The gems not used by other recipes will be used for magic item rerolling. - //Config.Recipes.push([Recipe.Reroll.Magic, 421]); // Reroll magic Diadem - //Config.Recipes.push([Recipe.Reroll.Magic, 605]); // Reroll magic Grand Charm (ilvl 91+) + //Config.Recipes.push([Recipe.Reroll.Magic, "Diadem"]); // Reroll magic Diadem + //Config.Recipes.push([Recipe.Reroll.Magic, "Grand Charm"]); // Reroll magic Grand Charm (ilvl 91+) - //Config.Recipes.push([Recipe.Reroll.Rare, 421]); // Reroll rare Diadem + //Config.Recipes.push([Recipe.Reroll.Rare, "Diadem"]); // Reroll rare Diadem /* Base item for the following recipes must be in pickit. The rest of the ingredients will be auto-picked. * Use Roll.Eth, Roll.NonEth or Roll.All to determine what kind of base item to roll - ethereal, non-ethereal or all. */ - //Config.Recipes.push([Recipe.Socket.Weapon, 255, Roll.Eth]); // Socket ethereal Thresher - //Config.Recipes.push([Recipe.Socket.Weapon, 256, Roll.Eth]); // Socket ethereal Cryptic Axe - //Config.Recipes.push([Recipe.Socket.Armor, 442, Roll.Eth]); // Socket ethereal Sacred Armor - //Config.Recipes.push([Recipe.Socket.Armor, 443, Roll.Eth]); // Socket ethereal Archon Plate + //Config.Recipes.push([Recipe.Socket.Weapon, "Thresher", Roll.Eth]); // Socket ethereal Thresher + //Config.Recipes.push([Recipe.Socket.Weapon, "Cryptic Axe", Roll.Eth]); // Socket ethereal Cryptic Axe + //Config.Recipes.push([Recipe.Socket.Armor, "Sacred Armor", Roll.Eth]); // Socket ethereal Sacred Armor + //Config.Recipes.push([Recipe.Socket.Armor, "Archon Plate", Roll.Eth]); // Socket ethereal Archon Plate - //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, 335, Roll.NonEth]); // Upgrade Bloodfist to Exceptional - //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, 337, Roll.NonEth]); // Upgrade Magefist to Exceptional - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 381, Roll.NonEth]); // Upgrade Bloodfist or Grave Palm to Elite - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 383, Roll.NonEth]); // Upgrade Magefist or Lavagout to Elite - //Config.Recipes.push([Recipe.Unique.Armor.ToElite, 389, Roll.NonEth]); // Upgrade Gore Rider to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, "Heavy Gloves", Roll.NonEth]); // Upgrade Bloodfist to Exceptional + //Config.Recipes.push([Recipe.Unique.Armor.ToExceptional, "Light Gauntlets", Roll.NonEth]); // Upgrade Magefist to Exceptional + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "Sharkskin Gloves", Roll.NonEth]); // Upgrade Bloodfist or Grave Palm to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "Battle Gauntlets", Roll.NonEth]); // Upgrade Magefist or Lavagout to Elite + //Config.Recipes.push([Recipe.Unique.Armor.ToElite, "War Boots", Roll.NonEth]); // Upgrade Gore Rider to Elite /* Runeword config. All recipes are available in Templates/Runewords.txt * Keep lines follow pickit format and any given runeword is tested vs ALL lines so you don't need to repeat them */ Config.MakeRunewords = false; // Set to true to enable runeword making/rerolling - //Config.Runewords.push([Runeword.Insight, 255]); // Thresher - //Config.Runewords.push([Runeword.Insight, 256]); // Cryptic Axe + //Config.Runewords.push([Runeword.Insight, "Thresher"]); // Make Insight Thresher + //Config.Runewords.push([Runeword.Insight, "Cryptic Axe"]); // Make Insight Cryptic Axe //Config.KeepRunewords.push("[type] == polearm # [meditationaura] == 17"); - //Config.Runewords.push([Runeword.Spirit, 447]); // Monarch - //Config.Runewords.push([Runeword.Spirit, 498]); // Sacred Targe + //Config.Runewords.push([Runeword.Spirit, "Monarch"]); // Make Spirit Monarch + //Config.Runewords.push([Runeword.Spirit, "Sacred Targe"]); // Make Spirit Sacred Targe //Config.KeepRunewords.push("[type] == shield || [type] == auricshields # [fcr] == 35"); @@ -366,15 +384,17 @@ function LoadConfig() { Config.DeathMessages = []; // Example: ["Watch out for that $killer, $name!"] Config.Congratulations = []; // Example: ["Congrats on level $level, $name!"] Config.ShitList = false; // Blacklist hostile players so they don't get invited to party. + Config.UnpartyShitlisted = false; // Leave party if someone invited a blacklisted player. // General config + Config.AutoMap = false; // Set to true to open automap at the beginning of the game. Config.LastMessage = ""; // Message or array of messages to say at the end of the run. Use $nextgame to say next game - "Next game: $nextgame" (works with lead entry point) Config.MinGameTime = 60; // Min game time in seconds. Bot will TP to town and stay in game if the run is completed before. Config.MaxGameTime = 0; // Maximum game time in seconds. Quit game when limit is reached. Config.TeleSwitch = false; // Switch to slot II when teleporting more than 1 node. Config.OpenChests = false; // Open chests. Controls key buying. Config.MiniShopBot = true; // Scan items in NPC shops. - Config.PacketShopping = false; // Use packets to shop. Imporves shopping speed. + Config.PacketShopping = false; // Use packets to shop. Improves shopping speed. Config.TownCheck = false; // Go to town if out of potions Config.LogExperience = false; // Print experience statistics in the manager. Config.PingQuit = [{Ping: 0, Duration: 0}]; // Quit if ping is over the given value for over the given time period in seconds. @@ -393,6 +413,7 @@ function LoadConfig() { Config.FBR = 0; // 0 - disable, 1 to 255 - set value of Faster Block Recovery. Config.IAS = 0; // 0 - disable, 1 to 255 - set value of Increased Attack Speed. Config.PacketCasting = 0; // 0 = disable, 1 = packet teleport, 2 = full packet casting. + Config.WaypointMenu = false; // Set to true for Single and private realms // Anti-hostile config Config.AntiHostile = false; // Enable anti-hostile. @@ -405,6 +426,7 @@ function LoadConfig() { Config.StopOnDClone = true; // Go to town and idle as soon as Diablo walks the Earth Config.SoJWaitTime = 5; // Time in minutes to wait for another SoJ sale before leaving game. 0 = disabled Config.KillDclone = false; // Go to Palace Cellar 3 and try to kill Diablo Clone. Pointless if you already have Annihilus. + Config.DCloneQuit = false; // 1 = quit when Diablo walks, 2 = quit on soj sales, 0 = disabled // Monster skip config // Skip immune monsters. Possible options: "fire", "cold", "lightning", "poison", "physical", "magic". @@ -432,6 +454,15 @@ function LoadConfig() { Config.LowManaSkill[0] = -1; // Timed low mana skill. Config.LowManaSkill[1] = -1; // Untimed low mana skill. + /* Advanced Attack config. Allows custom skills to be used on custom monsters. + * Format: "Monster Name": [timed skill id, untimed skill id] + * Example: "Baal": [38, -1] to use charged bolt on Baal + * Multiple entries are separated by commas + */ + Config.CustomAttack = { + //"Monster Name": [-1, -1] + }; + Config.Dodge = false; // Move away from monsters that get too close. Don't use with short-ranged attacks like Poison Dagger. Config.DodgeRange = 15; // Distance to keep from monsters. Config.DodgeHP = 100; // Dodge only if HP percent is less than or equal to Config.DodgeHP. 100 = always dodge. @@ -444,7 +475,7 @@ function LoadConfig() { // Class specific config Config.CastStatic = 60; // Cast static until the target is at designated life percent. 100 = disabled. - Config.StaticList = []; // List of monster NAMES to static. Example: Config.StaticList = ["Andariel", "Diablo", "Baal"]; + Config.StaticList = []; // List of monster NAMES or CLASSIDS to static. Example: Config.StaticList = ["Andariel", 243]; // AutoBuild System ( See /d2bs/kolbot/libs/config/Builds/README.txt for instructions ) diff --git a/d2bs/kolbot/libs/config/Templates/Attacks.txt b/d2bs/kolbot/libs/config/Templates/Attacks.txt index e29d6eb51..ddcfb921b 100644 --- a/d2bs/kolbot/libs/config/Templates/Attacks.txt +++ b/d2bs/kolbot/libs/config/Templates/Attacks.txt @@ -93,8 +93,8 @@ {skipped code} // Class specific config - Config.Curse[0] = 92; // Boss curse. Use skill number or set to 0 to disable. - Config.Curse[1] = 92; // Other monsters curse. Use skill number or set to 0 to disable. + Config.Curse[0] = 91; // Boss curse. Use skill number or set to 0 to disable. + Config.Curse[1] = 91; // Other monsters curse. Use skill number or set to 0 to disable. Config.ExplodeCorpses = 74; // Explode corpses. Use skill number or 0 to disable. 74 = Corpse Explosion, 83 = Poison Explosion @@ -158,9 +158,9 @@ Config.AttackSkill[0] = -1; // Preattack skill. Not implemented yet. Config.AttackSkill[1] = 97; // Primary skill to bosses. - Config.AttackSkill[2] = 113; // Primary aura to bosses - Config.AttackSkill[3] = 97; // Primary skill to others. - Config.AttackSkill[4] = 106; // Primary aura to others. + Config.AttackSkill[2] = 122; // Primary aura to bosses + Config.AttackSkill[3] = 106; // Primary skill to others. + Config.AttackSkill[4] = 122; // Primary aura to others. Config.AttackSkill[5] = -1; // Secondary skill if monster is immune to primary. Config.AttackSkill[6] = -1; // Secondary aura. diff --git a/d2bs/kolbot/libs/config/Templates/ShopBot.txt b/d2bs/kolbot/libs/config/Templates/ShopBot.txt index aa93d4d65..0a589f032 100644 --- a/d2bs/kolbot/libs/config/Templates/ShopBot.txt +++ b/d2bs/kolbot/libs/config/Templates/ShopBot.txt @@ -1,17 +1,2 @@ -For any classids I missed, check NTITemAlias.dbl file!! -Only items of high interest will be mentioned here. - -Item - classid - -Anya (hell): -Gauntlets - 338 -Light Plate (lld) - 327 -Mage Plate (lld) - 373 -Archon Plate - 443 -Ancient Armor - 326 -Barbed Shield (lld) - 397 -Ward - 449 -Greater Talons - 187 -Scissors Quhab - 188 -Runic Talons - 194 -Scissors Suwayyah - 195 \ No newline at end of file +Names can now be used instead of classids. If you want to use classids, check NTItemAlias.dbl +To see which NPC sells which items, check this link: http://members.iinet.net.au/~dcarson/shopcalc.html \ No newline at end of file diff --git a/d2bs/kolbot/pickit/Autoequip/READ.txt b/d2bs/kolbot/pickit/Autoequip/READ.txt new file mode 100644 index 000000000..92942407a --- /dev/null +++ b/d2bs/kolbot/pickit/Autoequip/READ.txt @@ -0,0 +1,6 @@ +This is an example autoequip pickit. +The feature is experimental and there will be ZERO support for it. +To use it, ADD these lines to your character config. + +Config.AutoEquip = true; +Config.PickitFiles.push("autoequip/sorceress.xpac.nip"); \ No newline at end of file diff --git a/d2bs/kolbot/pickit/Autoequip/sorceress.xpac.nip b/d2bs/kolbot/pickit/Autoequip/sorceress.xpac.nip new file mode 100644 index 000000000..bc6e30ea1 --- /dev/null +++ b/d2bs/kolbot/pickit/Autoequip/sorceress.xpac.nip @@ -0,0 +1,57 @@ +// weapon +//[type] == wand && [quality] <= rare # [fcr] > 0 && [maxmana] > 0 # [tier] == 1 +//[type] == wand && [quality] <= rare # [fcr] == 20 && [maxmana] >= 20 # [tier] == 2 +//[name] == blade && [quality] == unique # [fcr] > 0 # [tier] == 3 +//[name] == burntwand && [quality] == unique # [fcr] > 0 # [tier] == 4 +//[name] == swirlingcrystal && [quality] == set # # [tier] == 5 +[name] == swirlingcrystal && [quality] == set # [skillcoldmastery] == 2 # [tier] == 99 +[flag] == runeword # [plusskillbattleorders] > 0 # [tier] == 99 + +// armor +[type] == armor && [quality] <= rare # [maxhp] > 0 # [tier] == 1 +[name] == studdedleather && [quality] == unique # # [tier] == 2 +[name] == russetarmor && [quality] == unique && [flag] != ethereal # # [tier] == 3 +//[name] == hellforgeplate && [quality] == set # # [tier] == 4 +[name] == serpentskinarmor && [quality] == unique && [flag] != ethereal # [fireresist] < 35 # [tier] == 5 +[name] == lacqueredplate && [quality] == set # # [tier] == 101 + +// boots +[type] == boots && [quality] <= rare # [lightresist] > 0 # [tier] == 1 +[name] == battleboots && [quality] == set # # [tier] == 3 +[name] == heavyboots && [quality] == set # # [tier] == 4 +[name] == battleboots && [quality] == unique # [itemmagicbonus] < 40 # [tier] == 5 +[name] == battleboots && [quality] == unique # [itemmagicbonus] >= 40 # [tier] == 101 + +// gloves +[type] == gloves && [quality] <= rare # [maxhp] > 0 # [tier] == 1 +[name] == lightgauntlets && [quality] == unique # # [tier] == 2 +[name] == gauntlets && [quality] == unique # # [tier] == 3 + +// amulet +[type] == amulet && [quality] <= rare # [maxhp] > 0 && [maxmana] > 0 # [tier] == 1 +[type] == amulet && [quality] == unique # [itemallskills] == 1 # [tier] == 2 +[type] == amulet && [quality] == set # [sorceressskills] == 2 # [tier] == 101 + +// ring +[type] == ring && [quality] <= rare # [maxhp] > 0 # [tier] == 1 +[type] == ring && [quality] <= rare # [maxhp] > 0 && [fcr] == 10 # [tier] == 2 +[type] == ring && [quality] <= rare # [maxhp] > 0 && [maxmana] > 0 && [fcr] == 10 # [tier] == 3 +[type] == ring && [quality] == unique # [itemallskills] == 1 # [tier] == 100 + +// belt +[type] == belt && [quality] <= rare # [maxhp] > 0 # [tier] == 1 +[type] == belt && [quality] <= rare # [maxhp] > 0 && [fireresist]+[lightresist]+[coldresist] >= 30 # [tier] == 2 +[name] == meshbelt && [quality] == set # # [tier] == 3 +[name] == meshbelt && [quality] == set # [itemmagicbonus] == 15 # [tier] == 4 + +// helm +[type] == helm && [quality] == rare # [maxhp] > 0 # [tier] == 1 +[type] == helm && [quality] == rare # [maxhp] > 0 && [fireresist]+[lightresist]+[coldresist] >= 30 # [tier] == 2 +[name] == warhat && [quality] == unique # # [tier] == 3 +[name] == deathmask && [quality] == set # # [tier] == 4 + +// shield +[type] == shield && [quality] <= rare # [fireresist]+[lightresist]+[coldresist] >= 30 # [tier] == 1 +[type] == shield && [quality] <= rare # [fireresist]+[lightresist]+[coldresist] >= 50 # [tier] == 2 +[name] == grimshield && [quality] == unique # # [tier] == 3 +[name] == roundshield && [quality] == unique # # [tier] == 4 diff --git a/d2bs/kolbot/pickit/LLD.nip b/d2bs/kolbot/pickit/LLD.nip index f5f9389d3..d2a0a7e0b 100644 --- a/d2bs/kolbot/pickit/LLD.nip +++ b/d2bs/kolbot/pickit/LLD.nip @@ -24,6 +24,7 @@ //=== AMULETS ===================================================================================================================================================================== //================================================================================================================================================================================= +[name] == amulet && [quality] == magic # [paladinskills] == 1 && [maxhp] == 80 [name] == amulet && [quality] == magic # [palicombatskilltab]+[fireskilltab]+[poisonandboneskilltab]+[trapsskilltab]+[shapeshiftingskilltab] == 2 && ([maxhp] == 80 || [hpregen] == 15) [type] == amulet && [quality] == rare # [poisonandboneskilltab]+[fireskilltab]+[trapsskilltab]+[palicombatskilltab]+[coldskilltab]+[lightningskilltab]+[elementalskilltab] == 2 && [fcr] == 10 && [maxhp]+[maxmana] >= 50 && [itemlevelreq] <= 30 @@ -52,36 +53,37 @@ [type] == ring && [quality] == rare # ([dexterity] >= 4 || [strength] >= 4) && ([tohit] >= 70 || [mindamage] == 3) && [maxmana] >= 30 && [hpregen] >= 4 && [itemlevelreq] <= 18 [type] == ring && [quality] == rare # [fcr] == 10 && [strength] >= 4 && [hpregen] >= 4 && [maxmana] >= 30 && [itemlevelreq] <= 18 -[type] == ring && [quality] == rare # [dexterity] == 2 && [strength] == 2 && [tohit] >= 50 && [itemlevelreq] <= 9 -[type] == ring && [quality] == rare # [hpregen] >= 4 && [strength]+[dexterity] >= 2 && ([tohit] >= 50 || [maxmana] >= 11) && [itemlevelreq] <= 9 +[type] == ring && [quality] == rare # [tohit] >= 60 && [hpregen]+([strength]+[dexterity]+[maxdamage]+[maxmana]/5)*2 >= 7 && [itemlevelreq] <= 9 //================================================================================================================================================================================= //=== WEAPONS ===================================================================================================================================================================== //================================================================================================================================================================================= -([name] == broadsword || [name] == longsword) && [quality] == superior # ([sockets] == 0 || [sockets] == 4) && [enhanceddamage] == 15 && [tohit] == 3 // spirit -[name] == crystalsword && [quality] == superior # [sockets] == 4 && [enhanceddamage] == 15 && [tohit] == 3 // spirit -([name] == crowbill || [name] == naga) && [quality] == superior && [flag] != ethereal # ([sockets] == 0 || [sockets] == 5 || [sockets] == 6) && [enhanceddamage] == 15 && [tohit] == 3 // honor/robo -[name] == grimscythe && [quality] == superior && [flag] != ethereal # ([sockets] == 0 || [sockets] == 6) && [enhanceddamage] == 15 && [tohit] == 3 -[name] == knout && [quality] == superior # ([sockets] == 0 || [sockets] == 5) && [enhanceddamage] == 15 && [tohit] == 3 // honor -[name] == executionersword && [quality] == superior # ([sockets] == 0 || [sockets] == 5 || [sockets] == 6) && [enhanceddamage] == 15 && [tohit] == 3 // honor/robo +([name] == broadsword || [name] == longsword || [name] == runesword) && [quality] == superior # ([sockets] == 0 || [sockets] == 4) && [enhanceddamage] == 15 && [tohit] == 3 // spirit +[name] == crystalsword && [quality] == superior # [enhanceddamage] == 15 && [tohit] == 3 && [sockets] == 4 // spirit +([name] == crowbill || [name] == naga) && [quality] == superior && [flag] != ethereal # [enhanceddamage] == 15 && [tohit] == 3 && ([sockets] == 0 || [sockets] == 5 || [sockets] == 6) // honor/robo +[name] == grimscythe && [quality] == superior && [flag] != ethereal # [enhanceddamage] == 15 && [tohit] == 3 && ([sockets] == 0 || [sockets] == 6) +[name] == knout && [quality] == superior # [enhanceddamage] == 15 && [tohit] == 3 && ([sockets] == 0 || [sockets] == 5) // honor +[name] == executionersword && [quality] == superior # [enhanceddamage] == 15 && [tohit] == 3 && ([sockets] == 0 || [sockets] == 5 || [sockets] == 6) // honor/robo ([name] == warscepter || [name] == divinescepter) && [quality] <= superior # ([sockets] == 0 || [sockets] == 5) && [skillconcentration]+[skillblessedhammer] >= 5 [name] == divinescepter && [quality] <= superior && [flag] != ethereal # ([sockets] == 0 || [sockets] == 5) && [skillcharge]+[skillfanaticism] >= 5 ([name] == warscepter || [name] == divinescepter) && [quality] <= superior # ([sockets] == 0 || [sockets] == 5) && [skillfistoftheheavens]+[skillconviction] >= 5 [name] == divinescepter && [quality] <= superior && [flag] != ethereal # ([sockets] == 0 || [sockets] == 5) && [skillfanaticism]+[skillzeal] >= 5 ([name] == divinescepter || [name] == warscepter) && [quality] <= superior # ([sockets] == 0 || [sockets] == 5) && [skillholyshield] == 3 -[name] == ashwoodbow && [quality] == superior # ([sockets] == 0 || [sockets] == 5) && [bowandcrossbowskilltab] == 3 && [enhanceddamage] == 15 +[name] == ashwoodbow && [quality] == superior # [enhanceddamage] == 15 && [tohit] == 3 && [bowandcrossbowskilltab] == 3 && ([sockets] == 0 || [sockets] == 5) ([name] == shortsiegebow || [name] == ashwoodbow || [name] == runebow || [name] == doublebow) && [quality] == rare # [enhanceddamage]+[plusmaxdamage] >= 140 && ([sockets] == 2 || [ias] == 20) && [itemlevelreq] <= 30 +[name] == flail && [quality] == magic && [flag] != ethereal # ([sockets] == 3 || [palicombatskilltab] == 2) && [itemskillonhit] == 66 && [itemlevelreq] <= 30 // smiter flail +[name] == flail && [quality] == rare && [flag] != ethereal # [palicombatskilltab] == 2 && [sockets] == 2 && [ias] == 30 && [itemskillonhit] == 66 && [itemlevelreq] <= 30 // smiter flail +[name] == flail && [quality] == rare && [flag] == ethereal # [palicombatskilltab] == 2 && [sockets] == 2 && [ias] == 30 && [itemskillonhit] == 66 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 // smiter flail [name] == cutlass && [quality] == rare # [enhanceddamage]+[plusmaxdamage] >= 140 && [ias] == 30 && [sockets] == 2 && [itemlevelreq] <= 30 -[name] == cutlass && [quality] == rare && [flag] == ethereal # [enhanceddamage] >= 80 && [ias] == 30 && [sockets] == 2 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 -([name] == knout || [name] == naga || [name] == battlehammer) && [quality] == rare && [flag] == ethereal # [enhanceddamage] >= 140 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 -[name] == naga && [quality] == rare # [enhanceddamage]+[plusmaxdamage] >= 140 && ([ias] >= 20 || [sockets] == 2) && [itemlevelreq] <= 30 -[name] == naga && [quality] <= rare && [flag] == ethereal # [enhanceddamage] >= 80 && ([ias] >= 20 || [sockets] == 2) && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 -[name] == executionersword && [quality] == rare && [flag] != ethereal # [enhanceddamage]+[plusmaxdamage] >= 140 && ([ias] == 30 || [ias] >= 10 && [sockets] == 2) && [itemlevelreq] <= 30 -[name] == executionersword && [quality] == rare && [flag] == ethereal # [enhanceddamage] >= 80 && ([ias] == 30 || [ias] >= 10 && [sockets] == 2) && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 -([name] == warscepter || [name] == divinescepter) && [quality] <= rare # ([palicombatskilltab] == 2 || [sockets] == 3) && [skillfanaticism] == 3 && [amplifydamageonhit] > 0 && [itemlevelreq] <= 30 -[name] == harpoon && [quality] <= rare && [flag] == ethereal # [enhanceddamage] >= 80 && [itemreplenishquantity] > 0 && [itemlevelreq] <= 30 +[name] == cutlass && [quality] == rare && [flag] == ethereal # ([enhanceddamage]+[plusmaxdamage] >= 100 || [enhanceddamage] >= 50 && [itemskillonhit] == 66) && [ias] == 30 && [sockets] == 2 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 +([name] == knout || [name] == crowbill || [name] == divinescepter || [name] == runesword || [name] == zweihander) && [quality] <= rare && [flag] == ethereal # [enhanceddamage]+[plusmaxdamage] >= 100 && ([ias] >= 10 || [sockets] == 2) && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 +([name] == naga || [name] == ancientsword) && [quality] <= rare && [flag] == ethereal # [enhanceddamage]+[plusmaxdamage] >= 100 && ([ias] >= 20 || [sockets] == 2) && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 +[name] == executionersword && [quality] == rare && [flag] == ethereal # [enhanceddamage]+[plusmaxdamage] >= 100 && ([ias] == 30 || [ias] >= 10 && [sockets] == 2) && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 +[name] == battlehammer && [quality] == rare && [flag] == ethereal # [enhanceddamage]+[plusmaxdamage] >= 140 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 +([name] == warscepter || [name] == divinescepter) && [quality] <= rare # ([palicombatskilltab] == 2 || [sockets] == 3) && [skillfanaticism] == 3 && [itemskillonhit] == 66 && [itemlevelreq] <= 30 +[name] == harpoon && [quality] <= rare && [flag] == ethereal # [enhanceddamage]+[plusmaxdamage] >= 100 && [itemreplenishquantity] > 0 && [itemlevelreq] <= 30 //[name] == compositebow && [quality] == unique # [enhanceddamage] == 60 // Rogue Bow //[name] == longbattlebow && [quality] == unique # [passivecoldpierce] == 35 // Wizendraw @@ -92,17 +94,24 @@ [name] == warscepter && [quality] <= superior && [flag] != ethereal # ([sockets] == 0 || [sockets] == 5) && [skillzeal]+[skillconcentration] >= 6 && [itemlevelreq] <= 18 [name] == warscepter && [quality] <= superior && [flag] != ethereal # ([sockets] == 0 || [sockets] == 5) && [skillcharge]+[skillconcentration] >= 6 && [itemlevelreq] <= 18 -[name] == stagbow && [quality] == superior # ([sockets] == 0 || [sockets] == 5) && [enhanceddamage] == 15 && [tohit] == 3 && [bowandcrossbowskilltab] == 3 +[name] == stagbow && [quality] == superior # [enhanceddamage] == 15 && [tohit] == 3 && [bowandcrossbowskilltab] == 3 && ([sockets] == 0 || [sockets] == 5) ([name] == throwingspear || [name] == warjavelin) && [quality] <= rare && [flag] == ethereal # [enhanceddamage] > 50 && [itemreplenishquantity] > 0 && [itemlevelreq] <= 18 ([name] == bonewand || [name] == grimwand) && [quality] == magic # [poisonandboneskilltab] == 1 && [fcr] == 10 && [skillbonespear] == 3 && [itemlevelreq] <= 18 ([name] == bonewand || [name] == grimwand) && [quality] == rare # [poisonandboneskilltab] == 1 && [fcr] == 10 && [skillbonespear] == 3 && [sockets] == 2 && [itemlevelreq] <= 18 +[name] == flail && [quality] == rare && [flag] != ethereal # [ias] >= 20 && [sockets] >= 2 && [itemskillonhit] == 66 && [itemlevelreq] <= 18 // smiter/kicker +[name] == flail && [quality] == rare && [flag] == ethereal # [ias] >= 20 && [sockets] >= 2 && [itemskillonhit] == 66 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 18 // smiter/kicker +([name] == club || [name] == spikedclub || [name] == cudgel) && [quality] == rare # [elementalskilltab] == 1 && [maxhp] == 10 && [strength] == 5 && [itemlevelreq] <= 18 -[name] == warscepter && [quality] <= superior && [flag] != ethereal# ([sockets] == 0 || [sockets] == 5) && [skilldefiance]+[skillsacrifice] >= 6 && [itemlevelreq] <= 9 +([name] == waraxe || [name] == militarypick) && [quality] == superior && [flag] != ethereal # [enhanceddamage] == 15 && [tohit] == 3 && ([sockets] == 0 || [sockets] == 6) +[name] == warscepter && [quality] <= superior && [flag] != ethereal # [skilldefiance] >= 3 && ([sockets] == 0 || [sockets] == 5) && [itemlevelreq] <= 9 // spawns on ilvl < 37; 5 sockets at ilvl > 25 //[name] == throwingspear && [quality] <= rare && [flag] == ethereal # [itemreplenishquantity] > 0 && [itemlevelreq] <= 9 // basic -([name] == throwingspear || [name] == pilum) && [quality] == rare && [flag] == ethereal # [amplifydamageonhit] > 0 && [itemreplenishquantity] > 0 && [itemlevelreq] <= 9 -([name] == bladetalons || [name] == throwingspear) && [quality] <= rare && [flag] == ethereal # [enhanceddamage] >= 30 && [itemreplenishquantity] > 0 && [itemlevelreq] <= 9 -[name] == warscepter && [quality] <= rare && [suffix] == 605 && [flag] != ethereal # [enhanceddamage] >= 30 && [itemlevelreq] <= 9 // sacrifice -[type] == wand && [class] == normal && [quality] <= rare # [skillamplifydamage] == 3 && [skillbonearmor] == 3 && [skillclaygolem] == 3 && [itemlevelreq] <= 9 +([name] == throwingspear || [name] == pilum) && [quality] == rare && [flag] == ethereal # [itemskillonhit] == 66 && [itemreplenishquantity] > 0 && [itemlevelreq] <= 9 +[name] == throwingspear && [quality] <= rare && [flag] == ethereal # ([enhanceddamage] + [tohit]/2 + ([itemskillonhit] == 66)*15 + [ias]) >= 40 && [itemreplenishquantity] > 0 && [itemlevelreq] <= 9 +[name] == warscepter && [quality] <= rare && [flag] != ethereal # ([enhanceddamage] >= 40 || [tohit] >= 80 || [enhanceddamage] >= 30 && [tohit] >= 40) && [itemchargedskill] == 96 && [itemlevelreq] <= 9 // sacrifice +[name] == bladetalons && [quality] <= rare && [flag] != ethereal # ([enhanceddamage] >= 40 || [tohit] >= 80 || [enhanceddamage] >= 30 && [tohit] >= 40) && [itemskillonhit] == 66 && [itemlevelreq] <= 9 // BT of amplify damage +([name] == warscepter || [name] == flamberge || [name] == bladetalons || [name] == waraxe || [name] == warsword) && [quality] == rare && [flag] == ethereal # ([enhanceddamage]+[plusmaxdamage] >= 60 || [enhanceddamage]+[plusmaxdamage] >= 30 && [sockets] == 2 || [itemskillonhit] == 66) && [itemreplenishdurability] > 0 && [itemlevelreq] <= 9 + +[type] == wand && [class] == normal && [quality] <= rare # [skillamplifydamage]+[skillbonearmor] >= 6 && [itemlevelreq] <= 9 // spawns on ilvl < 25 //[name] == longsword && [quality] == set @@ -112,11 +121,11 @@ [name] == ancientarmor && [quality] == superior && [flag] != ethereal # [sockets] == 4 && [enhanceddefense] == 15 && ([itemmaxdurabilitypercent] == 15 || [itemmaxdurabilitypercent] == 0) -[name] == ornateplate && [quality] == magic # [enhanceddefense] == 100 && [itemreqpercent] < 0 && [itemlevelreq] <= 30 -[name] == ornateplate && [quality] == magic && [flag] == ethereal # [enhanceddefense] == 100 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 -[name] == mageplate && [quality] == magic # [sockets] == 3 && [maxhp] == 80 - -[name] == ornateplate && [quality] == rare && [flag] == ethereal # [enhanceddefense] >= 50 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 +[name] == ornateplate && [quality] == magic && [flag] != ethereal # [enhanceddefense] == 100 && [itemreqpercent] == -30 && [itemlevelreq] <= 30 +[name] == ornateplate && [quality] == magic && [flag] == ethereal # [enhanceddefense] >= 80 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 +([name] == lightplate || [name] == mageplate) && [quality] == magic # [sockets] == 3 && [maxhp] == 80 && [itemlevelreq] <= 30 + +[name] == ornateplate && [quality] == rare && [flag] == ethereal # [enhanceddefense] >= 60 && [itemreplenishdurability] > 0 && [sockets] == 2 && [itemlevelreq] <= 30 //[name] == studdedleather && [quality] == unique && [flag] != ethereal && [flag] != identified # [defense] == 35 // Twitchthroe //[name] == ghostarmor && [quality] == unique && [flag] != ethereal # [magicdamagereduction] == 11 // Spirit Shroud @@ -125,8 +134,11 @@ //---vlld------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -[name] == ancientarmor && [quality] <= rare && [flag] == ethereal # [enhanceddefense] >= 40 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 18 -[name] == ancientarmor && [quality] <= rare && [flag] == ethereal # [enhanceddefense] >= 20 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 9 +[name] == ancientarmor && [quality] == magic && [flag] == ethereal # [enhanceddefense] >= 40 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 18 +[name] == ancientarmor && [quality] == rare && [flag] == ethereal # [enhanceddefense] >= 30 && [itemreplenishdurability] > 0 && [sockets] == 2 && [itemlevelreq] <= 18 + +[name] == ancientarmor && [quality] == magic && [flag] == ethereal # [enhanceddefense] >= 30 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 9 +[name] == ancientarmor && [quality] == rare && [flag] == ethereal # [enhanceddefense] >= 20 && [itemreplenishdurability] > 0 && [sockets] == 2 && [itemlevelreq] <= 9 //================================================================================================================================================================================= //=== HELMS ======================================================================================================================================================================= @@ -135,8 +147,10 @@ [name] == crown && [quality] == superior && [flag] != ethereal # [enhanceddefense] == 15 && ([itemmaxdurabilitypercent] == 15 || [itemmaxdurabilitypercent] == 0) && [sockets] == 3 //[name] == grandcrown && [quality] == superior && [flag] != ethereal # [enhanceddefense] == 15 && ([itemmaxdurabilitypercent] == 15 || [itemmaxdurabilitypercent] == 0) && [sockets] == 3 +[type] == circlet && [quality] == magic && [flag] != ethereal # [paladinskills] == 1 && [maxhp] == 80 && [itemlevelreq] <= 30 [type] == circlet && [quality] == magic && [flag] != ethereal # [amazonskills]+[barbarianskills] == 1 && [frw] == 30 && [itemlevelreq] <= 30 [type] == circlet && [quality] == magic && [flag] != ethereal # [palicombatskilltab]+[fireskilltab]+[poisonandboneskilltab]+[trapsskilltab]+[elementalskilltab] == 2 && [fcr] == 20 && [itemlevelreq] <= 30 +[type] == circlet && [quality] == magic && [flag] != ethereal # [palicombatskilltab]+[fireskilltab]+[poisonandboneskilltab]+[trapsskilltab]+[elementalskilltab]+[shapeshiftingskilltab] == 2 && [maxhp] == 80 && [itemlevelreq] <= 30 ([name] == grandcrown || [name] == grandcrown || [name] == mask || [name] == deathmask) && [quality] == magic && [flag] != ethereal # [sockets] == 3 && [maxhp] >= 20 && [itemlevelreq] <= 30 [type] == circlet && [quality] == rare && [flag] != ethereal # [poisonandboneskilltab]+[fireskilltab]+[trapsskilltab] >= 2 && [fcr] == 20 && [frw] == 30 && [itemlevelreq] <= 30 @@ -145,18 +159,23 @@ [type] == circlet && [quality] == rare && [flag] != ethereal # [palicombatskilltab] >= 2 && [fcr] == 20 && [maxhp]+[maxmana] >= 50 && ([sockets] == 2 || [fireresist] >= 10 && [coldresist] >= 10 || [strength] == 9 || [hpregen] >= 6) && [itemlevelreq] <= 30 [type] == circlet && [quality] == rare && [flag] != ethereal # [coldskilltab] >= 2 && [fcr] == 20 && [maxhp]+[maxmana] >= 50 && ([sockets] == 2 || [fireresist] >= 10 && [coldresist] >= 10 || [strength] == 9 || [hpregen] >= 6) && [itemlevelreq] <= 30 [type] == circlet && [quality] == rare && [flag] != ethereal # [amazonskills]+[barbarianskills] == 1 && [frw] == 30 && ([sockets] == 2 || [maxhp]+[maxmana] >= 50 || [fireresist] >= 10 && [coldresist] >= 10 || [hpregen] >= 6) && [itemlevelreq] <= 30 -([name] == wingedhelm || [name] == grandcrown || [name] == deathmask || [name] == grimhelm) && [quality] == rare && [flag] == ethereal # [itemtohitpercentperlevel] > 0 && [enhanceddefense] >= 50 && ([itemreplenishdurability] > 0 || [itemreplenishquantity] > 0) && [itemlevelreq] <= 30 +([name] == wingedhelm || [name] == grandcrown || [name] == deathmask || [name] == grimhelm) && [quality] == rare && [flag] == ethereal # [itemtohitpercentperlevel] > 0 && [enhanceddefense] >= 50 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 ([name] == wingedhelm || [name] == grandcrown || [name] == deathmask || [name] == grimhelm) && [quality] == rare # [itemtohitpercentperlevel] > 0 && [enhanceddefense] >= 80 && [sockets] == 2 && [itemlevelreq] <= 30 //[name] == warhat && [quality] == unique && [flag] != ethereal # [hpregen] == 12 // Peasant Crown //---vlld------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -[type] == circlet && [quality] == magic && [flag] != ethereal # ([tohit] >= 120 || [itemtohitpercentperlevel] > 0 || [enhanceddamage] >= 30) && ([maxhp] >= 40 || [hpregen] >= 10 || [frw] == 20) && [itemlevelreq] <= 18 +[type] == circlet && [quality] == magic && [flag] != ethereal # ([tohit] >= 120 || [itemtohitpercentperlevel] > 0 || [enhanceddamage] >= 30 || [maxmana] >= 40) && ([maxhp] >= 40 || [hpregen] >= 10 || [frw] >= 20) && [itemlevelreq] <= 18 -[type] == circlet && [quality] == rare && [flag] != ethereal # [sockets] == 2 && [frw] == 20 && ([tohit] >= 100 || [maxdamage] >= 6 || [maxhp] >= 30 || [maxmana] >= 30 || [lightmaxdam] >= 100 || [hpregen] >= 8) && [itemlevelreq] <= 18 -[type] == circlet && [quality] <= rare && [flag] != ethereal # [poisonandboneskilltab]+[palicombatskilltab]+[fireskilltab]+[trapsskilltab] >= 1 && ([fcr] == 10 || [frw] == 20) && ([maxhp] >= 30 || [hpregen] >= 8 || [maxmana] >= 35 || [sockets] == 2) && [itemlevelreq] <= 18 +[type] == circlet && [quality] == rare && [flag] != ethereal # [sockets] == 2 && [frw] == 20 && ([enhanceddamage] >= 20 || [tohit] >= 100 || [maxdamage] >= 6 || [maxhp] >= 30 || [maxmana] >= 30 || [lightmaxdam] >= 100 || [hpregen] >= 8) && [itemlevelreq] <= 18 +[type] == circlet && [quality] == rare && [flag] != ethereal # [poisonandboneskilltab]+[palicombatskilltab]+[fireskilltab]+[trapsskilltab] >= 1 && ([fcr] == 10 || [frw] == 20) && ([maxhp] >= 30 || [hpregen] >= 8 || [maxmana] >= 35 || [sockets] == 2) && [itemlevelreq] <= 18 [type] == circlet && [quality] == rare && [flag] != ethereal # [poisonandboneskilltab]+[palicombatskilltab]+[fireskilltab]+[trapsskilltab] >= 1 && [fcr] == 10 && [frw] == 20 && [itemlevelreq] <= 18 +[name] == crown && [quality] == magic && [flag] == ethereal # [enhanceddefense] >= 50 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 18 +[name] == crown && [quality] == rare && [flag] == ethereal # [enhanceddefense] >= 50 && [sockets] == 2 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 18 + +[name] == crown && [quality] == magic && [flag] == ethereal # [enhanceddefense] >= 30 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 9 +[name] == crown && [quality] == rare && [flag] == ethereal # [enhanceddefense] >= 20 && [sockets] == 2 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 9 //================================================================================================================================================================================= //=== SHIELDS ===================================================================================================================================================================== @@ -164,22 +183,20 @@ //[name] == grimshield && [quality] == superior && [flag] != ethereal # [enhanceddefense] == 15 && [sockets] == 2 // for rhyme runeword -[name] == barbedshield && [quality] == magic # [fbr] == 30 && [palicombatskilltab] == 2 -//[name] == kiteshield && [quality] == magic # [fbr] == 30 && [sockets] == 3 -[name] == towershield && [quality] == magic # [fbr] == 30 && [sockets] == 3 && [defense] == 25 && [itemlevelreq] <= 30 -[name] == pavise && [quality] == magic # [fbr] == 30 && [sockets] == 3 && [defense] == 78 && [itemlevelreq] <= 30 -[name] == scutum && [quality] == magic # [fbr] == 30 && [sockets] == 3 && [defense] == 61 && [itemlevelreq] <= 30 -[name] == dragonshield && [quality] == magic # [fbr] == 30 && [sockets] == 3 && [defense] == 67 && [itemlevelreq] <= 30 +[name] == barbedshield && [quality] == magic && [flag] != ethereal # [fbr] == 30 && [palicombatskilltab] == 2 +//[name] == kiteshield && [quality] == magic && [flag] != ethereal # [fbr] == 30 && [sockets] == 3 +[name] == towershield && [quality] == magic && [flag] != ethereal # [fbr] == 30 && [sockets] == 3 && [defense] == 25 && [itemlevelreq] <= 30 +[name] == pavise && [quality] == magic && [flag] != ethereal # [fbr] == 30 && [sockets] == 3 && [defense] == 78 && [itemlevelreq] <= 30 +[name] == scutum && [quality] == magic && [flag] != ethereal # [fbr] == 30 && [sockets] == 3 && [defense] == 61 && [itemlevelreq] <= 30 +[name] == dragonshield && [quality] == magic && [flag] != ethereal # [fbr] == 30 && [sockets] == 3 && [defense] == 67 && [itemlevelreq] <= 30 [name] == barbedshield && [quality] == rare # [fbr] == 30 && [sockets] == 2 && [palicombatskilltab] == 2 && [itemlevelreq] <= 30 [name] == spikedshield && [quality] == rare # [fbr] == 30 && [sockets] == 2 && [fhr] == 17 && [itemlevelreq] <= 30 [name] == barbedshield && [quality] == rare # [fbr] == 30 && [sockets] == 2 && [fhr] == 17 && [itemlevelreq] <= 30 [name] == boneshield && [quality] == rare # [fbr] == 30 && [sockets] == 2 && [fhr] == 17 && [itemlevelreq] <= 30 [name] == grimshield && [quality] == rare # [fbr] == 30 && [sockets] == 2 && [fhr] == 17 && [itemlevelreq] <= 30 -[name] == spikedshield && [quality] == rare && [flag] == ethereal # [fbr] == 30 && [enhanceddefense] >= 66 && ([itemreplenishdurability] > 0 || [itemreplenishquantity] > 0) && [itemlevelreq] <= 30 -[name] == barbedshield && [quality] == rare && [flag] == ethereal # [fbr] == 30 && [enhanceddefense] >= 66 && ([itemreplenishdurability] > 0 || [itemreplenishquantity] > 0) && [itemlevelreq] <= 30 -[name] == boneshield && [quality] == rare && [flag] == ethereal # [fbr] == 30 && [enhanceddefense] >= 66 && ([itemreplenishdurability] > 0 || [itemreplenishquantity] > 0) && [itemlevelreq] <= 30 -[name] == grimshield && [quality] == rare && [flag] == ethereal # [fbr] == 30 && [enhanceddefense] >= 66 && ([itemreplenishdurability] > 0 || [itemreplenishquantity] > 0) && [itemlevelreq] <= 30 +[name] == barbedshield && [quality] == rare && [flag] == ethereal # [fbr] == 30 && [enhanceddefense] >= 100 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 +[name] == grimshield && [quality] == rare && [flag] == ethereal # [fbr] == 30 && [enhanceddefense] >= 100 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 30 //[name] == spikedshield && [quality] == unique && [flag] != ethereal # [enhanceddefense] == 60 // Swordback Hold //[name] == defender && [quality] == unique && [flag] != ethereal # [enhanceddefense] == 150 // Visceratuant @@ -188,6 +205,7 @@ [name] == boneshield && [quality] == magic # [fbr] == 30 && [itemdamagetomana] >= 12 [name] == boneshield && [quality] <= rare # [fbr] == 30 && [itemdamagetomana] >= 10 && [sockets] == 2 && [itemlevelreq] <= 9 +([name] == boneshield || [name] == gothicshield) && [quality] == rare && [flag] == ethereal # [fbr] == 30 && [enhanceddefense] >= 35 && [sockets] == 2 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 9 //================================================================================================================================================================================= //=== BELTS ======================================================================================================================================================================= @@ -230,6 +248,8 @@ //[name] == lightplatedboots && [quality] == unique && [flag] != ethereal # [enhanceddefense] == 60 // Goblin Toe //[name] == greaves && [quality] == unique && [flag] != ethereal # [enhanceddefense] == 80 // Tearhaunch +[type] == boots && [class] == normal && [quality] == rare && [flag] != ethereal # ([fhr] == 10 || [frw] == 10) && [dexterity] == 3 && [tohit] == 15 && [itemlevelreq] <= 9 + //================================================================================================================================================================================= //=== JEWELS ====================================================================================================================================================================== //================================================================================================================================================================================= @@ -238,17 +258,15 @@ [name] == jewel && [quality] == magic # [maxdamage] >= 24 && [itemlevelreq] <= 30 [name] == jewel && [quality] == magic # [enhanceddamage] == 20 && ([dexterity] == 9 || [strength] == 6 || [maxhp] == 8 || [maxdamage] == 15 || [itemreqpercent] < 0) -[name] == jewel && [quality] == rare # [dexterity] == 9 && [maxhp] == 8 && [itemlevelreq] <= 30 -[name] == jewel && [quality] == rare # [enhanceddamage]+[maxdamage]+[mindamage]*2 >= 45 && [itemlevelreq] <= 30 -[name] == jewel && [quality] == rare # ([mindamage] >= 4 || [enhanceddamage] >= 20) && [maxdamage] >= 18 && [itemlevelreq] <= 30 -[name] == jewel && [quality] <= rare # ([enhanceddamage] >= 20 || [maxdamage] >= 18 || [mindamage] >= 8) && ([defense] >= 30 || [strength]+[dexterity] >= 12 || [dexterity] >= 9 || [strength] >= 6 || [tohit] >= 50 || [itemreqpercent] < 0) && [itemlevelreq] <= 30 -[name] == jewel && [quality] == rare # [strength] >= 6 && [dexterity] >= 9 && [itemlevelreq] <= 30 -[name] == jewel && [quality] <= rare # ([maxdamage] >= 15 || [maxmana] >= 15) && [itemreqpercent] < 0 && [itemlevelreq] <= 30 +[name] == jewel && [quality] == rare # ([enhanceddamage] >= 18) + ([maxdamage] >= 9) * (([maxdamage] >= 16) + 1) + ([mindamage] >= 8) * (([mindamage] >= 10) + 1) + ([tohit] >= 40) >= 3 && [itemlevelreq] <= 30 +[name] == jewel && [quality] == rare # ([enhanceddamage] >= 18) + ([maxdamage] >= 9) * (([maxdamage] >= 16) + 1) + ([mindamage] >= 8) * (([mindamage] >= 10) + 1) + ([tohit] >= 40) >= 2 && ([dexterity] >= 8) + ([strength] >= 5) + ([defense] >= 30) + ([itemreqpercent] < 0) >= 1 && [itemlevelreq] <= 30 +[name] == jewel && [quality] == rare # ([enhanceddamage] >= 18 && [mindamage]+[maxdamage] == 0) + ([maxdamage] >= 9 && [enhanceddamage] == 0) * (([maxdamage] >= 16) + 1) + ([mindamage] >= 8 && [enhanceddamage] == 0) * (([mindamage] >= 10) + 1) + ([tohit] >= 40) + ([dexterity] >= 8) + ([strength] >= 5) + ([defense] >= 30) + ([itemreqpercent] < 0) + ([coldresist] >= 20 && [fireresist]+[lightresist] == 0 || [lightresist] >= 20 && [fireresist]+[coldresist] == 0 || [fireresist] >= 20 && [coldresist]+[lightresist] == 0) + ([coldresist] >= 35 || [lightresist] >= 35 || [fireresist] >= 35) * 2 >= 3 && [itemlevelreq] <= 30 +[name] == jewel && [quality] == rare # [dexterity] >= 8 && [strength] >= 5 && ([itemdamagetomana] >= 9) + ([maxmana] >= 10) * (([energy] >= 6) + 1) + ([itemreqpercent] < 0) + ([coldresist] >= 20 && [fireresist]+[lightresist] == 0 || [lightresist] >= 20 && [fireresist]+[coldresist] == 0 || [fireresist] >= 20 && [coldresist]+[lightresist] == 0) + ([coldresist] >= 35 || [lightresist] >= 35 || [fireresist] >= 35) * 2 >= 2 && [itemlevelreq] <= 30 //---vlld------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // 18 -[name] == jewel && [quality] <= rare # [maxdamage] >= 20 && [itemlevelreq] <= 18 +[name] == jewel && [quality] <= rare # ([maxdamage] >= 20 || [mindamage] == 4 && [maxdamage] == 15) && [itemlevelreq] <= 18 [name] == jewel && [quality] <= rare # [enhanceddamage] == 20 && ([maxdamage] == 15 || [dexterity] == 6) && [itemlevelreq] <= 18 // 9 @@ -256,12 +274,13 @@ [name] == jewel && [quality] <= rare # ([maxdamage] >= 14 || [mindamage] >= 8 || [mindamage] >= 4 && [maxdamage] >= 9) && [itemlevelreq] <= 9 [name] == jewel && [quality] <= rare # ([tohit] >= 40 || [enhanceddamage] >= 20 || [defense] >= 8) && ([maxdamage] >= 9 || [mindamage] >= 4) && [itemlevelreq] <= 9 [name] == jewel && [quality] <= rare # ([itemdamagetomana] == 12 || [maxmana] == 10) && ([dexterity] >= 3 || [maxhp] >= 8 || [itemreqpercent] < 0) && [itemlevelreq] <= 9 +[name] == jewel && [quality] <= rare # [enhanceddamage]*0.75 + [maxdamage]*1.8 + [mindamage]*2.5 + [tohit]*0.375 + [dexterity]*3.5 + ([maxhp]+[defense])*1.25 + [itemdamagetomana]/1.2 + ([itemreqpercent]/-1.5) >= 30 && [itemlevelreq] <= 9 //================================================================================================================================================================================= //=== STAVES ====================================================================================================================================================================== //================================================================================================================================================================================= -[type] == staff && [class] <= exceptional && [quality] == rare # [teleportcharges] > 0 && [fcr] == 20 && [itemlevelreq] <= 30 +[type] == staff && [class] <= exceptional && [quality] == rare # [itemchargedskill] == 54 && [fcr] == 20 && [itemlevelreq] <= 30 //================================================================================================================================================================================= //=== SMALL CHARMS ================================================================================================================================================================ @@ -269,7 +288,7 @@ //[name] == smallcharm && [quality] == magic # [maxhp] == 15 && [itemlevelreq] <= 30 //[name] == smallcharm && [quality] == magic # [frw] == 3 && [itemlevelreq] <= 30 -[name] == smallcharm && [quality] == magic # [maxhp] >= 13 && [maxdamage] >= 3 +[name] == smallcharm && [quality] == magic # [maxhp] >= 13 && [maxdamage] >= 3 && [itemlevelreq] <= 30 [name] == smallcharm && [quality] == magic # [maxhp] == 15 && ([poisonmaxdam] == 128 || [maxmana] >= 12 || [maxdamage] >= 3 || [defense] == 20 || [fireresist] >= 9 || [lightresist] >= 9 || [coldresist] >= 9 || [fireresist] >= 5 && [coldresist] >= 5) && [itemlevelreq] <= 30 [name] == smallcharm && [quality] == magic # [frw] == 3 && ([poisonmaxdam] == 128 || [maxmana] >= 12 || [maxdamage] >= 3 || [fireresist] >= 9 || [lightresist] >= 9 || [coldresist] >= 9 || [fireresist] >= 5 && [coldresist] >= 5) && [itemlevelreq] <= 30 @@ -297,7 +316,7 @@ //=== GRAND CHARMS ================================================================================================================================================================ //================================================================================================================================================================================= -[name] == grandcharm && [quality] == magic # [maxmana] >= 45 && ([maxhp] >= 20 || [fhr] == 12) && [itemlevelreq] <= 30 +[name] == grandcharm && [quality] == magic # [maxmana] == 46 && ([maxhp] == 25 || [fhr] == 12 || [frw] == 7) && [itemlevelreq] <= 30 [name] == grandcharm && [quality] == magic # [coldresist] == 15 && [fireresist] == 15 && ([frw] == 7 || [fhr] == 12) [name] == grandcharm && [quality] == magic # [maxdamage] == 10 && ([strength]+[dexterity] == 6 || [fhr] == 12 || [maxhp] >= 20 || [frw] == 7) && [itemlevelreq] <= 30 @@ -312,31 +331,37 @@ //---AMAZON------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ([name] == maidenjavelin || [name] == ceremonialjavelin) && [quality] <= rare && [flag] != ethereal # [javelinandspearskilltab] >= 4 && [ias] >= 30 && [itemlevelreq] <= 30 -[name] == ceremonialjavelin && [quality] <= rare && [flag] == ethereal # [enhanceddamage] >= 80 && ([itemreplenishdurability] > 0 || [itemreplenishquantity] > 0) && [itemlevelreq] <= 30 +[name] == ceremonialjavelin && [quality] <= rare && [flag] == ethereal # [enhanceddamage]+[plusmaxdamage] >= 100 && [itemreplenishquantity] > 0 && [itemlevelreq] <= 30 //---ASSASSIN---------------------------------------------------------------------------------------------------------------------------------------------------------------------- -[name] == handscythe && [quality] <= superior # [sockets] != 1 && [skilllightningsentry] == 3 && ([skillmindblast] >= 1 || [skilldragonflight] >= 1 || [skillweaponblock] == 3) +[name] == handscythe && [quality] <= superior # [sockets] != 1 && ([skilllightningsentry] == 3)+([skillmindblast] >= 3)+([skilldragonflight] >= 3)+([skillweaponblock] >= 3)+([skillshadowmaster] >= 3)+([skillbladeshield] >= 3) == 3 [name] == handscythe && [quality] <= rare # ([trapsskilltab] == 2 || [assassinskills] == 1) && ([skilllightningsentry] >= 3 || [skillwakeoffire] >= 3) && [itemlevelreq] <= 30 +//---vlld------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +[name] == bladetalons && [quality] <= rare && [flag] == ethereal # [enhanceddamage] >= 30 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 9 +[name] == bladetalons && [quality] <= rare && [flag] == ethereal # ([enhanceddamage] + [tohit]/2 + ([itemskillonhit] == 66)*15 + ([sockets] == 2)*20 + [ias]) >= 40 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 9 + //---BARBARIAN-------------------------------------------------------------------------------------------------------------------------------------------------------------------- -([name] == avengerguard || [name] == assaulthelmet) && [quality] <= superior && [class] <= exceptional # [skillwhirlwind] >= 2 && ([sockets] == 0 || [sockets] == 3) && [itemlevelreq] <= 30 +([name] == avengerguard || [name] == assaulthelmet) && [quality] <= superior && [flag] != ethereal # [skillwhirlwind] >= 2 && ([sockets] == 0 || [sockets] == 3) && [itemlevelreq] <= 30 -[type] == primalhelm && [quality] == magic && [class] <= exceptional # [skillwhirlwind] >= 2 && ([sockets] == 3 || [barbcombatskilltab] == 2 || [barbarianskills] == 1 || [maxhp] > 60) && [itemlevelreq] <= 30 +[type] == primalhelm && [quality] == magic && [class] <= exceptional # [skillwhirlwind] >= 2 && ([sockets] == 3 || [barbcombatskilltab] == 2 || [barbarianskills] == 1 || [maxhp] >= 50) && [itemlevelreq] <= 30 [type] == primalhelm && [quality] == rare && [class] <= exceptional # [skillwhirlwind] >= 2 && ([itemtohitpercentperlevel] > 0) && [itemlevelreq] <= 30 [type] == primalhelm && [quality] <= rare && [class] <= exceptional # [warcriesskilltab] == 2 && [skillbattleorders] == 3 && [itemlevelreq] <= 30 -[type] == primalhelm && [quality] <= superior # [skillthrowingmastery] == 3 && [itemlevelreq] <= 18 - //---vlld------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -[type] == primalhelm && [quality] <= superior # [skillshout] == 3 && ([sockets] == 3 || [sockets] == 0) && [itemlevelreq] <= 9 +[type] == primalhelm && [quality] <= superior # [skillthrowingmastery] == 3 && [itemlevelreq] <= 18 + +[type] == primalhelm && [quality] <= superior # [enhanceddefense] >= 15 && [skillshout] == 3 && ([sockets] == 3 || [sockets] == 0) && [itemlevelreq] <= 9 +[name] == fangedhelm && [quality] <= rare && [flag] == ethereal # [enhanceddefense] >= 30 && [skillshout] == 3 && [sockets] == 2 && [itemreplenishdurability] > 0 && [itemlevelreq] <= 9 //---DRUID------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -[type] == pelt && [quality] <= superior && [flag] != ethereal # [skillfury] == 3 && [skillheartofwolverine] > 0 && [itemlevelreq] <= 30 +[type] == pelt && [quality] <= superior && [flag] != ethereal # [skillfury] == 3 && [skillheartofwolverine] > 0 && ([sockets] == 0 || [sockets] == 3) && [itemlevelreq] <= 30 [type] == pelt && [quality] <= rare # [elementalskilltab] == 2 && ([skilltornado] == 3 || [skillfissure] == 3) && [itemlevelreq] <= 30 // 5 nado/fissure pelt [type] == pelt && [quality] <= rare # [shapeshiftingskilltab] == 2 && [skillfury] == 3 && ([itemtohitpercentperlevel] >= 1 || [sockets] == 2) && [itemlevelreq] <= 30 // 5 fury pelt @@ -347,13 +372,15 @@ //---NECROMANCER------------------------------------------------------------------------------------------------------------------------------------------------------------------ -[type] == voodooheads && [quality] <= superior # [skillbonespear] == 3 && [skillbonespirit] == 3 && [sockets] != 1 && [itemlevelreq] <= 30 +[type] == voodooheads && [quality] <= superior # [skillbonespear] >= 3 && [skillbonespirit] >= 3 && [sockets] != 1 && [itemlevelreq] <= 30 + +[type] == voodooheads && [quality] <= rare # [poisonandboneskilltab] >= 2 && [skillbonespirit] >= 3 && [fbr] == 30 && ([sockets] == 2 || [skillbonespear] == 3) && [itemlevelreq] <= 30 // vlld [type] == voodooheads && [quality] <= rare && [flag] != ethereal # [poisonandboneskilltab] == 1 && [fbr] == 30 && [skillbonespear] == 3 && [itemlevelreq] <= 18 -([name] == preservedhead || [name] == zombiehead) && [quality] <= rare # [skillamplifydamage] == 3 && [skillbonearmor] == 3 && [skillclaygolem] == 3 && [itemlevelreq] <= 9 +([name] == preservedhead || [name] == zombiehead) && [quality] <= rare # [skillamplifydamage]+[skillbonearmor] >= 6 && [itemlevelreq] <= 9 // spawns on ilvl < 25 //---PALADIN---------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -362,9 +389,8 @@ //---vlld------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -[name] == heraldicshield && [quality] <= superior && [flag] != ethereal # ([sockets] == 0 || [sockets] == 4) && [enhanceddamage] == 65 && [tohit] == 121 -[name] == crownshield && [quality] <= superior && [flag] != ethereal # ([sockets] == 0 || [sockets] == 4) && [enhanceddamage] == 65 && [tohit] == 121 -[name] == aerinshield && [quality] <= superior && [flag] != ethereal # ([sockets] == 0 || [sockets] == 4) && [enhanceddamage] == 65 && [tohit] == 121 +([name] == crownshield || [name] == heraldicshield || [name] == aerinshield) && [quality] <= superior && [flag] != ethereal # ([sockets] == 0 || [sockets] == 4) && [enhanceddamage] == 65 && [tohit] == 121 +[name] == rondache && [quality] <= superior && [flag] != ethereal # ([sockets] == 0 || [sockets] == 4) && [enhanceddamage] == 65 && [tohit] == 121 //---SORCERESS-------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/d2bs/kolbot/pickit/follower.nip b/d2bs/kolbot/pickit/follower.nip index 604464290..0b77c30ca 100644 --- a/d2bs/kolbot/pickit/follower.nip +++ b/d2bs/kolbot/pickit/follower.nip @@ -1,5 +1,3 @@ -// just a simple gold/pot pickit - [name] == gold [type] == healingpotion [type] == manapotion @@ -7,4 +5,59 @@ [quality] >= magic # [strength] > 100 -[type] == 39 \ No newline at end of file +[type] == 39 + +// classic + +// gloves +[type] == gloves # [maxhp] > 10 || [maxmana] > 10 # [tier] == 1 +[type] == gloves # [maxhp] > 10 && [maxmana] > 10 # [tier] == 2 +[name] == heavygloves && [quality] == unique # [maxhp] > 0 # [tier] == 3 +[name] == lightgauntlets && [quality] == unique # [fcr] > 0 # [tier] == 101 +[name] == lightgauntlets && [quality] == set # [coldresist] > 0 # [tier] == 101 + +// belt +[name] == lightbelt || [name] == sash # # [tier] == 1 +[name] == lightbelt # [maxhp] > 0 # [tier] == 2 +[name] == belt # [maxhp] > 0 # [tier] == 3 +[name] == heavybelt && [quality] == set # [mindamage] > 0 # [tier] == 101 + +// boots +[type] == boots # [fireresist]+[lightresist]+[coldresist] >= 10 # [tier] == 1 +[type] == boots # [fireresist]+[lightresist]+[coldresist] >= 40 # [tier] == 3 +[name] == greaves && [quality] == unique # [fireresist] > 0 # [tier] == 101 + +// helm +[type] == helm # [maxhp] > 0 # [tier] == 1 +[type] == helm && [quality] == rare # [maxhp] >= 30 && [fireresist]+[lightresist]+[coldresist] >= 40 # [tier] == 101 +[name] == crown && [quality] == set # [fireresist] > 0 # [tier] == 101 + +// amulet +[type] == amulet # [maxhp] > 0 # [tier] == 1 +[type] == amulet # [maxhp] > 0 && [maxmana] > 0 # [tier] == 2 +[type] == amulet && [quality] == unique # [itemallskills] == 1 # [tier] == 3 +[type] == amulet && [quality] == rare # [maxhp]+[maxmana] >= 50 && [fireresist]+[lightresist]+[coldresist] >= 40 # [tier] == 4 +[type] == amulet && [quality] == set # [poisonresist] > 0 # [tier] == 101 + +// ring +[type] == ring # [maxhp] > 0 # [tier] == 1 +[type] == ring # [maxhp] > 0 && [maxmana] > 0 # [tier] == 2 +[type] == ring && [quality] == unique # [maxmana] > 0 # [tier] == 3 +[type] == ring && [quality] == rare # [maxhp]+[maxmana] >= 40 && [fireresist]+[lightresist]+[coldresist] >= 30 # [tier] == 4 +[type] == ring && [quality] == unique # [itemallskills] == 1 # [tier] == 101 // soj + +// armor +[type] == armor # [maxhp] > 0 # [tier] == 1 +[type] == armor # [maxhp] >= 20 && [fireresist]+[lightresist]+[coldresist] >= 20 # [tier] == 2 +[name] == studdedleather && [quality] == unique # [dexterity] > 0 # [tier] == 101 + +// weapon +[type] == wand # [fcr] > 0 # [tier] == 1 +[type] == wand # [fcr] == 20 && [maxmana] >= 20 # [tier] == 2 +[name] == blade && [quality] == unique # [fcr] > 0 # [tier] == 101 + +// shield +[type] == shield # [fireresist]+[lightresist]+[coldresist] >= 10 # [tier] == 1 +[type] == shield # [fireresist]+[lightresist]+[coldresist] >= 20 # [tier] == 2 +[type] == shield # [fireresist]+[lightresist]+[coldresist] >= 40 # [tier] == 3 +[name] == gothicshield # [fireresist] > 0 # [tier] == 101 \ No newline at end of file diff --git a/d2bs/kolbot/pickit/kolton.nip b/d2bs/kolbot/pickit/kolton.nip index 6842eff06..cabc205d1 100644 --- a/d2bs/kolbot/pickit/kolton.nip +++ b/d2bs/kolbot/pickit/kolton.nip @@ -128,7 +128,7 @@ //([name] == demonhead || [name] == bonevisage) && [quality] == normal && [flag] == ethereal # [sockets] == 0 // ==unique== -//[name] == sallet && [quality] == unique && [flag] == ethereal # [enhanceddefense] >= 210 / /rockstopper +//[name] == sallet && [quality] == unique && [flag] == ethereal # [enhanceddefense] >= 210 // rockstopper [name] == grandcrown && [quality] == unique && [flag] != ethereal # [itemgoldbonus] >= 100 && [enhanceddefense] >= 200 && [lifeleech] >= 12 //crown of thieves [name] == grandcrown && [quality] == unique && [flag] == ethereal # [itemgoldbonus] >= 100 // crown of thieves eth [name] == grimhelm && [quality] == unique && [flag] == ethereal # [lifeleech] == 8 && [manaleech] == 8 && [magicdamagereduction] == 15 && [damageresist] >= 20 // vampgaze eth diff --git a/d2bs/kolbot/pickit/shopbot.nip b/d2bs/kolbot/pickit/shopbot.nip index 2fd07f932..c79ee9097 100644 --- a/d2bs/kolbot/pickit/shopbot.nip +++ b/d2bs/kolbot/pickit/shopbot.nip @@ -1,29 +1,16 @@ -// Use only this pickit when running Scripts.ShopBot for maximum speed -// Comment out the lines for items you don't want to scan +// Shopbot pickit for kolbot by kolton +// All lines are commented out. Remove the // at the beginning of a pickit line to search for the item. +// Early release version +// Last edit: 20.Nov.2014. -//[name] == greatertalons && [quality] == magic # ([assassinskills] == 2 || [trapsskilltab] == 3) && [skilllightningsentry] == 3 // 5/6LS GT -//([name] == greatertalons || [name] == runictalons) && [quality] == magic # [itemtohitperlevel] > 15 && [ias] >= 30 && [skilllightningsentry] == 3 // fool's ias LS claw -//([name] == greatertalons || [name] == runictalons) && [quality] == magic # [sockets] == 3 && [ias] >= 30 // 3os ias claw -//[type] == handtohand && [quality] == magic # ([assassinskills] == 2 || [trapsskilltab] == 3) && [skilllightningsentry] == 3 // 5/6LS any claw (gt/rt/sq/ss) -//[type] == handtohand && [quality] == magic # [shadowdisciplinesskilltab] == 3 && ([skillfade] == 3 || [skillvenom] == 3) // prebuff 6 venom or 6 fade claw -//([name] == lightplate || [name] == mageplate) && [quality] == magic # [sockets] == 3 && [maxhp] == 80 && [itemlevelreq] <= 30 // LLD -//([name] == ancientarmor || [name] == archonplate) && [quality] == magic # [sockets] == 4 && ([maxhp] >= 95 || [fhr] == 24) // 4os/95+ life or 4os/24fhr armor -//[name] == barbedshield && [quality] == magic # [palicombatskilltab] == 2 && [fbr] == 30 // LLD -//[type] == gloves && [quality] == magic # [javelinandspearskilltab] == 3 && [ias] == 20 // 3/20 gloves - -//[type] == scepter # [paladinskills] == 2 && [fcr] == 10 && ([skillconcentration] == 3 || [skillblessedhammer] == 3) -//[type] == scepter # [paladinskills] == 2 && [skillconcentration]+[skillblessedhammer] == 6 - -//[type] == staff # [sorceressskills]+[skillenchant] == 5 - -// =============== -// === Classic === -// =============== +// =============== +// ===== Classic ===== +// =============== // High level Paladin scepter (Ormus; Nightmare - Grand Scepter type, Hell - War Scepter type) -[type] == scepter # [paladinskills] == 2 && [fcr] == 10 && ([skillblessedhammer] == 3 || [skillconcentration] == 3) -[type] == scepter # [paladinskills] == 2 && [skillblessedhammer]+[skillconcentration] == 6 -[type] == scepter # [paladinskills] == 2 && [fcr] == 10 +//[type] == scepter # [paladinskills] == 2 && [fcr] == 10 && ([skillblessedhammer] == 3 || [skillconcentration] == 3) +//[type] == scepter # [paladinskills] == 2 && [skillblessedhammer]+[skillconcentration] == 6 +//[type] == scepter # [paladinskills] == 2 && [fcr] == 10 // Enchant staff (Ormus) //[type] == staff # [sorceressskills] == 2 && [skillenchant] == 3 // Any color (green is plain +2) @@ -35,59 +22,122 @@ //[name] == crystalsword # [barbarianskills] == 2 -// ================== -// === Expansion === -// ================== - -// VLLD lvl 9 Bone Shield (Anya, Ormus) -//[name] == boneshield # [fbr] == 30 && [itemdamagetomana] == 12 - -// VLLD lvl 9 sacrifice War Scepter (Ormus; Hell; Shop with a level 95+ character to get level 11 charges) -//[name] == warscepter # ([enhanceddamage] >= 40 || [tohit] >= 80 || [enhanceddamage] >= 30 && [tohit] >= 40) && [itemchargedskill] == 96 && [itemlevelreq] <= 9 - -// VLLD lvl 18 wand (Ormus) -//[name] == bonewand || [name] == grimwand # [fcr] == 10 && [poisonandboneskilltab] == 1 && [skillbonespear] == 3 && [itemlevelreq] <= 18 - -// VLLD lvl 18 scepter (Ormus) -//[type] == scepter # [palicombatskilltab] == 1 && [fcr] == 10 && [skillconcentration]+[skillblessedhammer] == 6 && [itemlevelreq] <= 18 - -// LLD lvl 30 wand -//[type] == wand # [poisonandboneskilltab] == 2 && [fcr] == 20 && [skillbonespear]+[skillbonespirit] == 6 && [itemlevelreq] <= 30 - -// LLD lvl 30 Paladin scepters (Ormus) -//[name] == warscepter || [name] == divinescepter # [sockets] == 3 && [skillfanaticism] == 3 && [itemskillonhit] == 66 && [itemlevelreq] <= 30 -//[type] == scepter # [palicombatskilltab] == 2 && [fcr] == 10 && [skillconcentration]+[skillblessedhammer] == 6 && [itemlevelreq] <= 30 - -// LLD lvl 30 Hand Scythe - WoF, LS (Fara, Elzix; Nightmare) -//[name] == handscythe # ([trapsskilltab] == 2 || [assassinskills] == 1) && [skillwakeoffire] == 3 && [itemlevelreq] <= 30 -//[name] == handscythe # ([trapsskilltab] == 2 || [assassinskills] == 1) && [skilllightningsentry] == 3 && [itemlevelreq] <= 30 - -// LLD lvl 30 Cutlass - Fury (Fara, Elzix; Nightmare) -//[name] == cutlass # [enhanceddamage] == 100 && [ias] == 30 && [itemlevelreq] <= 30 - -// LLD lvl 30 Smiter Amplify Damage Mace (Fara; Flail - Hell, Knout - Nightmare) -//[name] == flail # [sockets] == 3 && [itemskillonhit] == 66 && [itemlevelreq] <= 30 -//[name] == knout # [sockets] == 3 && [itemskillonhit] == 66 && [itemlevelreq] <= 30 - -// LLD lvl 30 shields - perfect defense (Fara; Nightmare) -// [name] == towershield # [defense] == 25 && [fbr] == 30 && [sockets] == 3 && [itemlevelreq] <= 30 -// [name] == dragonshield # [defense] == 67 && [fbr] == 30 && [sockets] == 3 && [itemlevelreq] <= 30 -// [name] == pavise # [defense] == 78 && [fbr] == 30 && [sockets] == 3 && [itemlevelreq] <= 30 - -// Paladin scepters - FoH, BH, HS (Ormus) -//[type] == scepter # ([paladinskills] == 2 || [palicombatskilltab] == 3) && [skillconcentration]+[skillblessedhammer] == 6 -//[type] == scepter # ([paladinskills] == 2 || [palicombatskilltab] == 3) && [skillfistoftheheavens]+[skillconviction] == 6 -//[type] == scepter # [palicombatskilltab]+[skillholyshield] == 6 - -// Fury Druid Fanged Knife (Malah) -//[name] == fangedknife # [enhanceddamage] == 300 && [ias] == 40 - -// BO switch Crystal Sword (Ormus) -//[name] == crystalsword # [warcriesskilltab] == 3 && [strength] == 30 - -// 4-socketed Gothic Plate (Ormus) -//[name] == gothicplate # [sockets] == 4 && [maxhp] == 100 -//[name] == gothicplate # [sockets] == 4 && [fhr] == 24 - -// Amazon gloves (Nightmare) -// [type] == gloves # [javelinandspearskilltab] == 3 && [ias] == 20 \ No newline at end of file +// ==================== +// ====== Expansion ====== +// ==================== + +// Contents for easy search (Ctrl+F): +// category search phrase +// +// level 9 shields $9s +// level 9 weapons $9w +// level 18 weapons $18w +// level 30 armor $30a +// level 30 shields $30s +// level 30 weapons $30w +// high lvl shields $hs +// high lvl armor $ha +// high lvl weapons $hw +// high lvl gloves $hg +// high lvl belts $hbl +// high lvl boots $hbt + + +// ==== Level 9 ==== + +// --- Shields [$9s] --- +//[name] == boneshield # [fbr] == 30 && [itemdamagetomana] == 12 // [N]Dronan, [N]Ormus, [N]Anya + +// --- Weapons [$9w] --- +//[name] == warscepter # ([enhanceddamage] >= 40 || [tohit] >= 80 || [enhanceddamage] >= 30 && [tohit] >= 40) && [itemchargedskill] == 96 && [itemlevelreq] <= 9 // [H]Akara, [H]Drognan, [H]Ormus, [H]Jamella, [H]Malah; level 95+ char for level 11 charges +//[name] == bladetalons # ([enhanceddamage] >= 40 || [tohit] >= 80 || [enhanceddamage] >= 30 && [tohit] >= 40) && [ias] == 10 && [itemlevelreq] <= 9 // [H]Anya +//[type] == wand && [quality] <= superior # [skillclaygolem]+[skillamplifydamage]+[skillbonearmor] == 9 && [itemlevelreq] <= 9 // [N]Akara, [N]Drognan + + +// ==== Level 18 ==== + +// --- Weapons [$18w] --- + +//[name] == bonewand || [name] == grimwand # [fcr] == 10 && [poisonandboneskilltab] == 1 && [skillbonespear] == 3 && [itemlevelreq] <= 18 // [H]Akara, [H]Drognan, [H]Ormus, [H]Jamella +//[type] == scepter && [quality] <= superior # [skillconcentration]+[skillblessedhammer] == 6 && [itemlevelreq] <= 18 // [N]Drognan; **Level <= 19 character at [H]Akara, [H]Drognan, [H]Ormus etc. +//[type] == scepter # [palicombatskilltab] == 1 && [fcr] == 10 && [skillconcentration]+[skillblessedhammer] == 6 && [itemlevelreq] <= 18 // [H]Akara, [H]Drognan, [H]Ormus etc. +//[type] == scepter # [palicombatskilltab] == 1 && [hpregen] >= 10 && [skillconcentration]+[skillblessedhammer] == 6 && [itemlevelreq] <= 18 // [H]Akara, [H]Drognan, [H]Ormus etc. + + +// ==== Level 30 ==== + +// --- Armor [$30a] --- +//[name] == breastplate && [quality] == magic # [sockets] == 3 && [maxhp] == 80 && [itemlevelreq] <= 30 // [NM]Fara +//[name] == lightplate && [quality] == magic # [sockets] == 3 && [maxhp] == 80 && [itemlevelreq] <= 30 // [H]Anya +//[name] == mageplate && [quality] == magic # [sockets] == 3 && [maxhp] == 80 && [itemlevelreq] <= 30 // [H]Anya + +// --- Shields [$30s] --- +//[name] == kiteshield # [defense] == 18 && [fbr] == 30 && [sockets] == 3 && [itemlevelreq] <= 30 // [NM]Fara +//[name] == towershield # [defense] == 25 && [fbr] == 30 && [sockets] == 3 && [itemlevelreq] <= 30 // [NM]Fara +//[name] == dragonshield # [defense] == 67 && [fbr] == 30 && [sockets] == 3 && [itemlevelreq] <= 30 // [NM]Fara +//[name] == pavise # [defense] == 78 && [fbr] == 30 && [sockets] == 3 && [itemlevelreq] <= 30 // [NM]Fara +//[name] == pavise # [enhanceddefense] == 100 && [fbr] == 30 && [itemlevelreq] <= 30 // [NM]Fara +//[name] == barbedshield && [quality] == magic # [palicombatskilltab] == 2 && [fbr] == 30 // [NM]Drognan, [H]Anya + +// --- Weapons [$30w] --- +//([name] == bonewand || [name] == grimwand) && [quality] <= superior # [skillbonespear]+[skillclaygolem]+[skillgolemmastery] == 9 && ([sockets] == 0 || [sockets] == 2) // [N]Drognan; **Level <= 19 character at [H]Akara, [H]Drognan, [H]Ormus etc. +//[type] == wand # [poisonandboneskilltab] == 2 && [fcr] == 20 && [skillbonespear]+[skillbonespirit] == 6 && [itemlevelreq] <= 30 // [H]Drognan, [H]Ormus, etc. +//[type] == scepter # [palicombatskilltab] == 2 && [skillconcentration]+[skillblessedhammer] == 6 && [itemlevelreq] <= 30 // [H]Akara, [H]Drognan, [H]Ormus etc. +//[type] == scepter # [palicombatskilltab] == 2 && [fcr] == 10 && [skillconcentration]+[skillblessedhammer] == 6 && [itemlevelreq] <= 30 // [H]Akara, [H]Drognan, [H]Ormus etc. +//[name] == warscepter || [name] == divinescepter # [sockets] == 3 && [skillfanaticism] == 3 && [itemskillonhit] == 66 && [itemlevelreq] <= 30 // [H]Akara, [H]Drognan, [H]Ormus etc. +//[name] == handscythe # ([trapsskilltab] == 2 || [assassinskills] == 1) && [skillwakeoffire] == 3 && [itemlevelreq] <= 30 // [NM]Fara, [NM]Elzix +//[name] == handscythe # ([trapsskilltab] == 2 || [assassinskills] == 1) && [skilllightningsentry] == 3 && [itemlevelreq] <= 30 // [NM]Fara, [NM]Elzix +//[name] == cutlass # [palicombatskilltab] == 2 && [itemskillonhit] == 66 && [itemlevelreq] <= 30 // [NM]Fara, [NM]Elzix +//[name] == cutlass # [enhanceddamage] == 100 && [ias] == 30 && [itemlevelreq] <= 30 // [NM]Fara, [NM]Elzix +//[name] == flail # [sockets] == 3 && [itemskillonhit] == 66 && [itemlevelreq] <= 30 // [H]Fara +//[name] == knout # [sockets] == 3 && [itemskillonhit] == 66 && [itemlevelreq] <= 30 // [NM]Fara + + +// ==== High Level ==== + +// --- Weapons [$hw] --- +//[type] == scepter # ([paladinskills] == 2 || [palicombatskilltab] == 3) && [skillconcentration]+[skillblessedhammer] == 6 // [H]Akara, [H]Drognan, [H]Ormus etc. +//[type] == scepter # ([paladinskills] == 2 || [palicombatskilltab] == 3) && [skillfistoftheheavens]+[skillconviction] == 6 // [H]Akara, [H]Drognan, [H]Ormus etc. +//[type] == scepter # [palicombatskilltab]+[skillholyshield] == 6 // [H]Akara, [H]Drognan, [H]Ormus etc. +//[name] == fangedknife # [enhanceddamage] == 300 && [ias] == 40 // [H]Fara, [H]Malah +//[name] == cinquedeas # [enhanceddamage] == 300 && [ias] == 40 // [NM]Fara, [H]Fara, [NM]Malah, [H]Malah +//[name] == crystalsword # [warcriesskilltab] == 3 && [strength] == 30 // [H]Ormus +//[name] == barbedclub # [warcriesskilltab] == 3 && [strength] == 30 // [NM]Elzix +//[name] == mace # [warcriesskilltab] == 3 && [strength] == 30 // [NM]Elzix +//[name] == morningstar # [warcriesskilltab] == 3 && [strength] == 30 // [NM]Fara, [NM]Elzix +//[name] == giantsword # [warcriesskilltab] == 3 && [strength] == 30 // [NM]Fara +//[name] == giantsword # [warcriesskilltab] == 3 && [itemskillonattack] == 39 // [NM]Fara +//[name] == greatertalons && [quality] == magic # [assassinskills] == 2 && [skilllightningsentry] == 3 // [H]Anya +//[name] == greatertalons && [quality] == magic # [trapsskilltab] == 3 && [skilllightningsentry] == 3 // [H]Anya +//([name] == greatertalons || [name] == runictalons) && [quality] == magic # [itemtohitperlevel] > 15 && [ias] >= 30 && [skilllightningsentry] == 3 // [H]Anya +//([name] == greatertalons || [name] == runictalons) && [quality] == magic # [sockets] == 3 && [ias] >= 30 && [skillvenom] == 3 // [H]Anya +//[type] == handtohand && [quality] == magic # [assassinskills] == 2 && [skilllightningsentry] == 3 // [H]Anya +//[type] == handtohand && [quality] == magic # [trapsskilltab] == 3 && [skilllightningsentry] == 3 // [H]Anya +//[type] == handtohand && [quality] == magic # [shadowdisciplinesskilltab] == 3 && ([skillfade] == 3 || [skillvenom] == 3) // [H]Anya +//[type] == handtohand && [quality] == magic # [shadowdisciplinesskilltab] == 3 && [skillfade]+[skillvenom] == 6 // [H]Anya + +// --- Armor [$ha] --- +//[name] == breastplate && [quality] == superior && [flag] != ethereal # [sockets] == 3 && [enhanceddefense] == 15 && [itemmaxdurabilitypercent] == 15 // [N]Fara +//[name] == ringmail && [quality] == superior && [flag] != ethereal # [sockets] == 3 && [enhanceddefense] == 15 && [itemmaxdurabilitypercent] == 15 // [N]Fara +//[name] == gothicplate && [quality] == magic # [sockets] == 4 && [maxhp] == 100 // [H]Ormus +//[name] == gothicplate && [quality] == magic # [sockets] == 4 && [fhr] == 24 // [H]Ormus +//[name] == archonplate && [quality] == magic # [sockets] == 4 && [maxhp] == 100 // [H]Anya +//[name] == archonplate && [quality] == magic # [sockets] == 4 && [fhr] == 24 // [H]Anya +//[name] == ancientarmor && [quality] == magic # [sockets] == 4 && [maxhp] == 100 // [H]Anya +//[name] == ancientarmor && [quality] == magic # [sockets] == 4 && [fhr] == 24 // [H]Anya + +// --- Gloves [$hg] --- +//[type] == gloves # [javelinandspearskilltab] == 3 && [ias] == 20 // [H]Anya, [NM]Fara etc. + +// --- Boots [$hbl] --- +//[type] == boots # [itemgoldbonus] == 80 && [fireresist] == 40 // [H]Anya +//[type] == boots # [maxmana] == 40 && [frw] == 40 // [H]Anya + +// --- Boots [$hbt] --- +//[type] == belt && [name] >= platedbelt # [itemgoldbonus] == 80 && [fireresist] == 30 // [NM]Fara + +// ============================= +// ====== Temporary/Unsorted ====== +// ============================= + +//[name] == handscythe && [quality] == magic && [level] >= 90 # # [maxquantity] == 1 \ No newline at end of file diff --git a/d2bs/kolbot/tools/AntiHostile.js b/d2bs/kolbot/tools/AntiHostile.js index a6de91f9c..723f7edf6 100644 --- a/d2bs/kolbot/tools/AntiHostile.js +++ b/d2bs/kolbot/tools/AntiHostile.js @@ -10,6 +10,7 @@ include("json2.js"); include("NTItemParser.dbl"); include("OOG.js"); include("Gambling.js"); +include("CraftingSystem.js"); include("common/Attack.js"); include("common/Cubing.js"); include("common/Config.js"); @@ -26,17 +27,13 @@ include("common/Town.js"); function main() { // Variables and functions - var player, findTrigger, attackCount, prevPos, check, missile, + var player, attackCount, prevPos, check, missile, charClass = ["Amazon", "Sorceress", "Necromancer", "Paladin", "Barbarian", "Druid", "Assassin"], hostiles = []; // AntiHostile gets game event info from ToolsThread this.scriptEvent = function (msg) { switch (msg.split(" ")[0]) { - case "findHostiles": // Scan for hostile players - findTrigger = true; - - break; case "remove": // Remove a hostile player that left the game if (hostiles.indexOf(msg.split(" ")[1]) > -1) { hostiles.splice(hostiles.indexOf(msg.split(" ")[1]), 1); @@ -89,24 +86,6 @@ function main() { } }; - // Initiate flashing sequence - this.startFlash = function (gid) { - var script = getScript("tools/FlashThread.js"); - - if (script) { - script.send("flash " + gid); - } - }; - - // Abort flashing sequence - this.stopFlash = function () { - var script = getScript("tools/FlashThread.js"); - - if (script) { - script.send("unflash"); - } - }; - // Find hostile player Units this.findPlayer = function () { var i, player; @@ -171,38 +150,14 @@ function main() { Attack.init(); Storage.Init(); - // Load flash thread - if (Config.HostileAction > 1) { - load("tools/FlashThread.js"); - } + // Use PVP range for attacks + Skill.usePvpRange = true; // Attack sequence adjustments - this only affects the AntiHostile thread switch (me.classid) { - case 0: // Amazon - increase skill range - if ([24].indexOf(Config.AttackSkill[1]) > -1) { - ClassAttack.skillRange[1] = 40; - ClassAttack.skillRange[2] = 40; - } - - break; - case 1: // Sorceress - increase skill range - if ([47, 49, 51, 53, 56, 59].indexOf(Config.AttackSkill[1]) > -1) { - ClassAttack.skillRange[1] = 40; - ClassAttack.skillRange[2] = 40; - } - - break; - case 2: // Necromancer - increase skill range - if ([84, 93].indexOf(Config.AttackSkill[1]) > -1) { - ClassAttack.skillRange[1] = 40; - ClassAttack.skillRange[2] = 40; - } - - break; case 6: // Assassin - use Mind Blast with trapsins if (me.getSkill(273, 1) && [251, 256].indexOf(Config.AttackSkill[1]) > -1) { Config.AttackSkill[1] = 273; // Mind Blast - ClassAttack.skillRange[1] = 40; ClassAttack.trapRange = 40; } @@ -230,17 +185,12 @@ function main() { addEventListener("scriptmsg", this.scriptEvent); print("ÿc2Anti-Hostile thread loaded."); - this.findHostiles(); // Main Loop while (true) { if (me.gameReady) { // Scan for hostiles - if (findTrigger) { - this.findHostiles(); - - findTrigger = false; - } + this.findHostiles(); if (hostiles.length > 0 && (Config.HostileAction === 0 || (Config.HostileAction === 1 && me.inTown))) { if (Config.TownOnHostile) { @@ -270,10 +220,10 @@ function main() { while (!this.findPlayer() && hostiles.length > 0) { if (!me.getState(121)) { - Skill.cast(Config.AttackSkill[1], ClassAttack.skillHand[1], 15099, 5237); + Skill.cast(Config.AttackSkill[1], Skill.getHand(Config.AttackSkill[1]), 15099, 5237); } else { if (Config.AttackSkill[2] > -1) { - Skill.cast(Config.AttackSkill[2], ClassAttack.skillHand[2], 15099, 5237); + Skill.cast(Config.AttackSkill[2], Skill.getHand(Config.AttackSkill[2]), 15099, 5237); } else { while (me.getState(121)) { delay(40); @@ -295,7 +245,7 @@ function main() { while (!this.findPlayer() && hostiles.length > 0) { // Tornado path is a function of target x. Slight randomization will make sure it can't always miss - Skill.cast(Config.AttackSkill[1], ClassAttack.skillHand[1], 15099 + rand(-2, 2), 5237); + Skill.cast(Config.AttackSkill[1], Skill.getHand(Config.AttackSkill[1]), 15099 + rand(-2, 2), 5237); } break; @@ -313,7 +263,7 @@ function main() { } } - Skill.cast(Config.AttackSkill[1], ClassAttack.skillHand[1], 15099, 5237); + Skill.cast(Config.AttackSkill[1], Skill.getHand(Config.AttackSkill[1]), 15099, 5237); while (me.getState(121)) { delay(40); @@ -361,7 +311,6 @@ function main() { } this.pause(); - this.startFlash(player.gid); // might need to be expanded Config.UseMerc = false; // Don't go revive the merc mid-fight attackCount = 0; @@ -383,7 +332,7 @@ function main() { if (missile) { do { if (getPlayerFlag(me.gid, missile.owner, 8) && (getDistance(me, missile) < 15 || (missile.targetx && getDistance(me, missile.targetx, missile.targety) < 15))) { - this.moveAway(missile, ClassAttack.skillRange[1]); + this.moveAway(missile, Skill.getRange(Config.AttackSkill[1])); break; } @@ -391,8 +340,8 @@ function main() { } // Move away if the player is too close or if he tries to move too close (telestomp) - if (ClassAttack.skillRange[1] > 20 && (getDistance(me, player) < 30 || (player.targetx && getDistance(me, player.targetx, player.targety) < 15))) { - this.moveAway(player, ClassAttack.skillRange[1]); + if (Skill.getRange(Config.AttackSkill[1]) > 20 && (getDistance(me, player) < 30 || (player.targetx && getDistance(me, player.targetx, player.targety) < 15))) { + this.moveAway(player, Skill.getRange(Config.AttackSkill[1])); } break; @@ -416,7 +365,6 @@ function main() { Pather.moveTo(prevPos.x, prevPos.y); this.resume(); - this.stopFlash(); } } diff --git a/d2bs/kolbot/tools/AutoBuildThread.js b/d2bs/kolbot/tools/AutoBuildThread.js index 2a8fea7ad..6f6db82d4 100644 --- a/d2bs/kolbot/tools/AutoBuildThread.js +++ b/d2bs/kolbot/tools/AutoBuildThread.js @@ -160,7 +160,7 @@ function spendSkillPoint (id) { } else { AutoBuild.print("Fake useSkillPoint(): "+skillName); } - delay(100); // TODO: How long should we wait... if at all? + delay(200); // TODO: How long should we wait... if at all? return (unusedSkillPoints - me.getStat(5) === 1); // Check if we spent one point }; @@ -210,7 +210,7 @@ function spendSkillPoints () { } } - delay(100); // TODO: How long should we wait... if at all? + delay(200); // TODO: How long should we wait... if at all? } return spentEveryPoint; @@ -232,6 +232,7 @@ function main () { var levels = gainedLevels(); if (levels > 0 && canSpendPoints()) { + scriptBroadcast("toggleQuitlist"); AutoBuild.print("Level up detected (", prevLevel, "-->", me.charlvl, ")"); spendSkillPoints(); spendStatPoints(); @@ -245,6 +246,8 @@ function main () { // prevLevel doesn't get set to me.charlvl because // we may have gained multiple levels at once prevLevel += 1; + + scriptBroadcast("toggleQuitlist"); } delay(1e3); diff --git a/d2bs/kolbot/tools/CloneKilla.js b/d2bs/kolbot/tools/CloneKilla.js index 4f750e64a..e28763792 100644 --- a/d2bs/kolbot/tools/CloneKilla.js +++ b/d2bs/kolbot/tools/CloneKilla.js @@ -1 +1 @@ -/** * @filename CloneKilla.js * @author kolton * @desc Kill Diablo Clone when he walks in game. Uses Fire Eye location. */ include("json2.js"); include("NTItemParser.dbl"); include("OOG.js"); include("AutoMule.js"); include("Gambling.js"); include("TorchSystem.js"); include("MuleLogger.js"); include("common/Attack.js"); include("common/Cubing.js"); include("common/CollMap.js"); include("common/Config.js"); include("common/Loader.js"); include("common/Misc.js"); include("common/Pickit.js"); include("common/Pather.js"); include("common/Precast.js"); include("common/Prototypes.js"); include("common/Runewords.js"); include("common/Storage.js"); include("common/Town.js"); function main() { D2Bot.init(); Config.init(); Pickit.init(); Attack.init(); Storage.Init(); Runewords.init(); Cubing.init(); include("bots/KillDclone.js"); Config.TownHP = 0; Config.TownMP = 0; Config.TownCheck = 0; if (typeof KillDclone === "function") { try { D2Bot.printToConsole("Trying to kill DClone.", 7); KillDclone.call(); } catch (e) { Misc.errorReport(e, "CloneKilla.js"); } } quit(); return true; } \ No newline at end of file +/** * @filename CloneKilla.js * @author kolton * @desc Kill Diablo Clone when he walks in game. Uses Fire Eye location. */ include("json2.js"); include("NTItemParser.dbl"); include("OOG.js"); include("AutoMule.js"); include("craftingsystem.js"); include("Gambling.js"); include("TorchSystem.js"); include("MuleLogger.js"); include("common/Attack.js"); include("common/Cubing.js"); include("common/CollMap.js"); include("common/Config.js"); include("common/Loader.js"); include("common/Misc.js"); include("common/Pickit.js"); include("common/Pather.js"); include("common/Precast.js"); include("common/Prototypes.js"); include("common/Runewords.js"); include("common/Storage.js"); include("common/Town.js"); function main() { D2Bot.init(); Config.init(); Pickit.init(); Attack.init(); Storage.Init(); CraftingSystem.buildLists(); Runewords.init(); Cubing.init(); include("bots/KillDclone.js"); if (typeof KillDclone === "function") { try { D2Bot.printToConsole("Trying to kill DClone.", 7); KillDclone.call(); } catch (e) { Misc.errorReport(e, "CloneKilla.js"); } } quit(); return true; } \ No newline at end of file diff --git a/d2bs/kolbot/tools/FlashThread.js b/d2bs/kolbot/tools/FlashThread.js deleted file mode 100644 index aba04ed28..000000000 --- a/d2bs/kolbot/tools/FlashThread.js +++ /dev/null @@ -1,36 +0,0 @@ -function main() { - include("common/misc.js"); - - var i, - flashList = []; - - addEventListener('scriptmsg', - function (msg) { - if (msg.split(" ")[0] === "flash") { - print("Flash away!"); - flashList.push(msg.split(" ")[1]); - } - - if (msg === "unflash") { - print("Stopping flash."); - flashList = []; - } - } - ); - - while (true) { - if (me.gameReady) { - if (flashList.length > 0) { - for (i = 0; i < flashList.length; i += 1) { - Packet.flash(flashList[i]); - - if (i < flashList.length - 1) { - delay(100); - } - } - } - } - - delay(100); - } -} \ No newline at end of file diff --git a/d2bs/kolbot/tools/HeartBeat.js b/d2bs/kolbot/tools/HeartBeat.js index fb52ca15e..5b2421a68 100644 --- a/d2bs/kolbot/tools/HeartBeat.js +++ b/d2bs/kolbot/tools/HeartBeat.js @@ -11,69 +11,44 @@ function main() { D2Bot.init(); print("Heartbeat loaded"); - var tick = getTickCount(), - startTick = getTickCount(); - - function scriptCheck() { - if (getTickCount() - startTick < 2000) { - return false; - } - - /*if (!me.ingame && getLocation() && getScript("default.dbj")) { - D2Bot.printToConsole("default.dbj was loaded out of game."); - D2Bot.restart(); - - return true; - }*/ - - var list = [], - threads = [], - script = getScript(); + function togglePause() { + var script = getScript(); if (script) { do { - if (list.indexOf(script.name) === -1) { - list.push(script.name); - threads.push(script.threadid); - } else if (script.threadid !== threads[list.indexOf(script.name)]) { - D2Bot.printToConsole("Script loaded twice " + script.name); - D2Bot.restart(); - - return true; + if (script.name.indexOf(".dbj") > -1) { + if (script.running) { + print("ÿc1Pausing ÿc0" + script.name); + script.pause(); + } else { + print("ÿc2Resuming ÿc0" + script.name); + script.resume(); + } } } while (script.getNext()); } - return false; + return true; } - function CopyDataEvent(mode, msg) { - switch (mode) { - case 4: - if (msg === "pingrep") { - tick = getTickCount(); + // Event functions + function KeyEvent(key) { + switch (key) { + case 19: + if (me.ingame) { + break; } + togglePause(); + break; } } - addEventListener("copydata", CopyDataEvent); + addEventListener("keyup", KeyEvent); while (true) { D2Bot.heartBeat(); delay(1000); - - /*sendCopyData(null, me.windowtitle, 4, "pingreq"); - delay(500); - - if (getTickCount() - tick >= 20000) { - D2Bot.printToConsole("Starter not responding."); - D2Bot.restart(); - }*/ - - if (scriptCheck()) { - break; - } } } \ No newline at end of file diff --git a/d2bs/kolbot/tools/MapHelper.js b/d2bs/kolbot/tools/MapHelper.js index 40bec6723..09d15d97f 100644 --- a/d2bs/kolbot/tools/MapHelper.js +++ b/d2bs/kolbot/tools/MapHelper.js @@ -1 +1 @@ -include("json2.js"); include("NTItemParser.dbl"); include("OOG.js"); include("AutoMule.js"); include("Gambling.js"); include("TorchSystem.js"); include("MuleLogger.js"); include("common/Attack.js"); include("common/Cubing.js"); include("common/CollMap.js"); include("common/Config.js"); include("common/Loader.js"); include("common/Misc.js"); include("common/Pickit.js"); include("common/Pather.js"); include("common/Precast.js"); include("common/Prototypes.js"); include("common/Runewords.js"); include("common/Storage.js"); include("common/Town.js"); function main() { include("json2.js"); var obj, action; Config.init(); Pickit.init(); Storage.Init(); addEventListener("scriptmsg", function (msg) { action = msg; }); while (true) { while (!me.gameReady) { delay(100); } if (action) { try { obj = JSON.parse(action); if (obj) { switch (obj.type) { case "area": Pather.moveToExit(obj.dest, true); break; case "unit": Pather.moveToUnit(obj.dest, true); break; case "wp": Pather.getWP(me.area); break; } } } catch (e) { } action = false; } delay(100); } } \ No newline at end of file +include("json2.js"); include("NTItemParser.dbl"); include("OOG.js"); include("AutoMule.js"); include("Gambling.js"); include("TorchSystem.js"); include("MuleLogger.js"); include("common/Attack.js"); include("common/Cubing.js"); include("common/CollMap.js"); include("common/Config.js"); include("common/Loader.js"); include("common/Misc.js"); include("common/Pickit.js"); include("common/Pather.js"); include("common/Precast.js"); include("common/Prototypes.js"); include("common/Runewords.js"); include("common/Storage.js"); include("common/Town.js"); function main() { include("json2.js"); var obj, action, mapThread = getScript("tools/mapthread.js"); Config.init(); Pickit.init(); Storage.Init(); addEventListener("scriptmsg", function (msg) { action = msg; }); while (true) { if (getUIFlag(0x09)) { delay(100); if (mapThread.running) { print("pause mapthread"); mapThread.pause(); } } else { if (!mapThread.running) { print("resume mapthread"); mapThread.resume(); } } if (action) { try { obj = JSON.parse(action); if (obj) { switch (obj.type) { case "area": Pather.moveToExit(obj.dest, true); break; case "unit": Pather.moveToUnit(obj.dest, true); break; case "wp": Pather.getWP(me.area); break; } } } catch (e) { } action = false; } delay(20); } } \ No newline at end of file diff --git a/d2bs/kolbot/tools/MapThread.js b/d2bs/kolbot/tools/MapThread.js index d2da5eb32..05038d37f 100644 --- a/d2bs/kolbot/tools/MapThread.js +++ b/d2bs/kolbot/tools/MapThread.js @@ -424,15 +424,16 @@ var Hooks = { hooks: [], action: null, currArea: 0, + enabled: true, prevAreas: [0, 0, 1, 2, 3, 10, 5, 6, 2, 3, 4, 6, 7, 9, 10, 11, 12, 3, 17, 17, 6, 20, 21, 22, 23, 24, 7, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 4, 1, 1, 40, 41, 42, 43, 44, 74, 40, 47, 48, 40, 50, 51, 52, 53, 41, 42, 56, 45, 55, 57, 58, 43, 62, 63, 44, 46, 46, 46, 46, 46, - 46, 46, 1, 54, 1, 75, 76, 76, 78, 79, 80, 81, 82, 76, 76, 78, 86, 78, 88, 87, 89, 80, 92, 80, 80, 81, 81, 82, 82, 83, 100, 101, 102, + 46, 46, 1, 54, 1, 75, 76, 76, 78, 79, 80, 81, 82, 76, 76, 78, 86, 78, 88, 87, 89, 81, 92, 80, 80, 81, 81, 82, 82, 83, 100, 101, 102, 103, 104, 105, 106, 107, 103, 109, 110, 111, 112, 113, 113, 115, 115, 117, 118, 118, 109, 121, 122, 123, 111, 112, 117, 120, 128, 129, 130, 131, 109, 109, 109, 109], + event: function (keycode) { Hooks.tele.action = keycode; }, - enabled: true, check: function () { if (!this.enabled) { @@ -466,6 +467,11 @@ var Hooks = { hook = this.getHook("POI"); obj.type = "unit"; + break; + case 100: // Numpad 4 + hook = this.getHook("Side Area"); + obj.type = "area"; + break; } @@ -503,6 +509,65 @@ var Hooks = { nextAreas[46] = getRoom().correcttomb; } + switch (me.area) { + case 2: // Blood Moor + this.hooks.push({ + name: "Side Area", + destination: 8, + hook: new Text("Num 4: " + Pather.getAreaName(8), 150, 525 - (this.hooks.length * 10)) + }); + + break; + case 43: // Far Oasis + this.hooks.push({ + name: "Side Area", + destination: 62, + hook: new Text("Num 4: " + Pather.getAreaName(62), 150, 525 - (this.hooks.length * 10)) + }); + + break; + case 76: + this.hooks.push({ + name: "Side Area", + destination: 85, + hook: new Text("Num 4: " + Pather.getAreaName(85), 150, 525 - (this.hooks.length * 10)) + }); + + break; + case 78: + this.hooks.push({ + name: "Side Area", + destination: 88, + hook: new Text("Num 4: " + Pather.getAreaName(88), 150, 525 - (this.hooks.length * 10)) + }); + + break; + case 80: + this.hooks.push({ + name: "Side Area", + destination: 94, + hook: new Text("Num 4: " + Pather.getAreaName(94), 150, 525 - (this.hooks.length * 10)) + }); + + break; + case 81: + this.hooks.push({ + name: "Side Area", + destination: 92, + hook: new Text("Num 4: " + Pather.getAreaName(92), 150, 525 - (this.hooks.length * 10)) + }); + + break; + case 113: + this.hooks.push({ + name: "Side Area", + destination: 114, + hook: new Text("Num 4: " + Pather.getAreaName(114), 150, 525 - (this.hooks.length * 10)) + }); + + break; + } + poi = Hooks.vector.getPOI(); if (poi) { @@ -648,10 +713,10 @@ function main() { case 104: // Numpad 8 if (Hooks.vector.enabled) { Hooks.vector.enabled = false; - Hooks.text.getHook("vectorStatus").hook.text = "Num 8: Enable Vectors"; + Hooks.text.getHook("vectorStatus").hook.text = "Num 8: Enable Monsters"; } else { Hooks.vector.enabled = true; - Hooks.text.getHook("vectorStatus").hook.text = "Num 8: Disable Vectors"; + Hooks.text.getHook("vectorStatus").hook.text = "Num 8: Disable Monsters"; } break; diff --git a/d2bs/kolbot/tools/Party.js b/d2bs/kolbot/tools/Party.js index 8787b73c4..e606c3cea 100644 --- a/d2bs/kolbot/tools/Party.js +++ b/d2bs/kolbot/tools/Party.js @@ -11,6 +11,7 @@ function main() { include("common/Cubing.js"); include("common/Runewords.js"); include("common/Misc.js"); + include("common/Prototypes.js"); Config.init(); var i, myPartyId, player, otherParty, shitList, currScript, scriptList, @@ -68,9 +69,9 @@ function main() { } }); - print("ÿc2Party thread loaded. Mode: " + (Config.PublicMode > 1 ? "Accept" : "Invite")); + print("ÿc2Party thread loaded. Mode: " + (Config.PublicMode === 2 ? "Accept" : "Invite")); - if (Config.ShitList) { + if (Config.ShitList || Config.UnpartyShitlisted) { shitList = ShitList.read(); print(shitList.length + " entries in shit list."); @@ -132,13 +133,30 @@ function main() { otherParty = player.partyid; } - if (player.partyflag === 2 && (!otherParty || player.partyid === otherParty) && (getTickCount() - partyTick >= 2000)) { + if (player.partyflag === 2 && (!otherParty || player.partyid === otherParty) && (getTickCount() - partyTick >= 2000 || Config.FastParty)) { clickParty(player, 2); delay(100); } break; } + + if (Config.UnpartyShitlisted) { + // Add new hostile players to temp shitlist, leader should have Config.ShitList set to true to update the permanent list. + if (getPlayerFlag(me.gid, player.gid, 8) && shitList.indexOf(player.name) === -1) { + shitList.push(player.name); + } + + if (shitList.indexOf(player.name) > -1 && myPartyId !== 65535 && player.partyid === myPartyId) { + // Only the one sending invites should say this. + if ([1, 3].indexOf(Config.PublicMode) > -1) { + say(player.name + " is shitlisted. Do not invite them."); + } + + clickParty(player, 3); + delay(100); + } + } } } diff --git a/d2bs/kolbot/tools/RushThread.js b/d2bs/kolbot/tools/RushThread.js index bdb2a5f1b..2f924ca0b 100644 --- a/d2bs/kolbot/tools/RushThread.js +++ b/d2bs/kolbot/tools/RushThread.js @@ -11,6 +11,7 @@ include("NTItemParser.dbl"); include("OOG.js"); include("Gambling.js"); include("AutoMule.js"); +include("CraftingSystem.js"); include("TorchSystem.js"); include("common/Attack.js"); include("common/Cubing.js"); @@ -97,6 +98,7 @@ function main() { }; this.andariel = function () { + say("starting andariel"); Town.doChores(); Pather.useWaypoint(35, true); Precast.doPrecast(true); @@ -135,6 +137,7 @@ function main() { this.cube = function () { if (me.diff === 0) { + say("starting cube"); Pather.useWaypoint(57, true); Precast.doPrecast(true); @@ -161,6 +164,7 @@ function main() { }; this.amulet = function () { + say("starting amulet"); Town.doChores(); Pather.useWaypoint(44, true); Precast.doPrecast(true); @@ -193,6 +197,7 @@ function main() { }; this.staff = function () { + say("starting staff"); Town.doChores(); Pather.useWaypoint(43, true); Precast.doPrecast(true); @@ -225,6 +230,7 @@ function main() { // right down 25830 5447 (25866, 5431) // left down 25447 5822 (25431, 5861) + say("starting summoner"); Town.doChores(); Pather.useWaypoint(74, true); Precast.doPrecast(true); @@ -300,6 +306,8 @@ function main() { }; this.duriel = function () { + say("starting duriel"); + if (me.inTown) { Town.doChores(); Pather.useWaypoint(46, true); @@ -312,13 +320,7 @@ function main() { } Pather.makePortal(); - - if (me.diff < 2) { - Attack.securePosition(me.x, me.y, 30, 3000, true); - } else { - Attack.securePosition(me.x, me.y, 25, 3000, true, true); - } - + Attack.securePosition(me.x, me.y, 30, 3000, true, me.diff === 2); say("1"); while (!this.playerIn()) { @@ -353,9 +355,16 @@ function main() { delay(100); } - Pather.usePortal(null, me.name); + if (!Pather.usePortal(null, me.name)) { + Town.goToTown(); + } + + Pather.useWaypoint(52); + Pather.moveToExit([51, 50], true); + Pather.moveTo(10022, 5047); say("a3"); - Pather.useWaypoint(75, true); + Town.goToTown(3); + Town.doChores(); while (!this.playersInAct(3)) { delay(250); @@ -365,83 +374,95 @@ function main() { }; this.travincal = function () { + say("starting travincal"); Town.doChores(); Pather.useWaypoint(83, true); Precast.doPrecast(true); var coords = [me.x, me.y]; - Pather.moveTo(coords[0] - 24, coords[1]); - Pather.moveTo(coords[0] - 24, coords[1] - 135); - Pather.moveTo(coords[0] + 81, coords[1] - 135); + Pather.moveTo(coords[0] + 23, coords[1] - 102); Pather.makePortal(); - Attack.securePosition(me.x, me.y, 25, 3000); + Attack.securePosition(me.x, me.y, 40, 3000); say("1"); while (!this.playerIn()) { - Pather.moveTo(coords[0] + 81, coords[1] - 135); delay(250); } - Pather.moveTo(coords[0] + 97, coords[1] - 68); - Attack.kill(getLocaleString(2863)); + Pather.moveTo(coords[0] + 30, coords[1] - 134); + Pather.moveTo(coords[0] + 86, coords[1] - 130); + Pather.moveTo(coords[0] + 71, coords[1] - 94); + Attack.securePosition(me.x, me.y, 40, 3000); + + /*Attack.kill(getLocaleString(2863)); Attack.kill(getLocaleString(2862)); - Attack.kill(getLocaleString(2860)); + Attack.kill(getLocaleString(2860));*/ + say("2"); - Pather.moveTo(coords[0] + 81, coords[1] - 135); + Pather.moveTo(coords[0] + 23, coords[1] - 102); Pather.usePortal(null, me.name); return true; }; this.mephisto = function () { + say("starting mephisto"); + + var hydra; + Town.doChores(); Pather.useWaypoint(101, true); Precast.doPrecast(true); Pather.moveToExit(102, true); - Pather.moveTo(17591, 8070); - - var monsta, - monList = []; - - monsta = getUnit(1); + Pather.moveTo(17692, 8023); + Pather.makePortal(); + delay(2000); + say("1"); - if (monsta) { - do { - if (Attack.checkMonster(monsta) && getDistance(monsta, 17627, 8070) <= 30) { - monList.push(copyUnit(monsta)); - } - } while (monsta.getNext()); + while (!this.playerIn()) { + delay(250); } - if (monList.length) { - Pather.moveTo(17627, 8070); - Attack.clearList(monList); + Pather.moveTo(17591, 8070); + Attack.kill(242); + Pickit.pickItems(); + Pather.moveTo(17692, 8023); + Pather.makePortal(); + say("2"); + + while (this.playerIn()) { + delay(250); } Pather.moveTo(17591, 8070); - Pather.makePortal(); + Attack.securePosition(me.x, me.y, 40, 3000); - monsta = getUnit(1, "hydra"); + hydra = getUnit(1, "hydra"); - if (monsta) { + if (hydra) { do { - while (monsta.mode !== 0 && monsta.mode !== 12 && monsta.hp > 0) { + while (hydra.mode !== 0 && hydra.mode !== 12 && hydra.hp > 0) { delay(500); } - } while (monsta.getNext()); + } while (hydra.getNext()); } + Pather.makePortal(); + Pather.moveTo(17581, 8070); say("1"); while (!this.playerIn()) { - Pather.moveTo(17591, 8070); delay(250); } - Attack.kill(242); say("a4"); - Pather.moveTo(17591, 8070); + //Pather.moveTo(17591, 8070); + + while (!this.playersInAct(4)) { + delay(250); + } + delay(2000); Pather.usePortal(null); @@ -449,6 +470,8 @@ function main() { }; this.diablo = function () { + say("starting diablo"); + this.getLayout = function (seal, value) { var sealPreset = getPresetUnit(108, 2, seal); @@ -624,6 +647,7 @@ function main() { } Attack.kill(243); + say("2"); if (me.gametype > 0) { say("a5"); @@ -659,6 +683,8 @@ function main() { return false; } + say("starting ancients"); + var altar; Town.doChores(); @@ -711,21 +737,7 @@ function main() { }; this.baal = function () { - if (me.diff === 2) { - say("Hell rush complete~"); - delay(500); - quit(); - - return false; - } - - if (!this.bumperCheck()) { - say("No eligible bumpers detected. Rush complete~"); - delay(500); - quit(); - - return false; - } + say("starting baal"); var tick, portal; @@ -867,12 +879,14 @@ function main() { return true; }; - Town.doChores(); - Pather.useWaypoint(129, true); - Precast.doPrecast(true); + if (me.inTown) { + Town.doChores(); + Pather.useWaypoint(129, true); + Precast.doPrecast(true); - if (!Pather.moveToExit([130, 131], true)) { - throw new Error("Failed to move to Throne of Destruction."); + if (!Pather.moveToExit([130, 131], true)) { + throw new Error("Failed to move to Throne of Destruction."); + } } Pather.moveTo(15113, 5040); @@ -944,6 +958,7 @@ MainLoop: delay(10); } + this.clearThrone(); Pather.moveTo(15092, 5011); Precast.doPrecast(true); @@ -961,7 +976,9 @@ MainLoop: throw new Error("Couldn't find portal."); } + Pather.moveTo(15213, 5908); Pather.makePortal(); + Pather.moveTo(15170, 5950); delay(1000); say("3"); @@ -983,12 +1000,19 @@ MainLoop: }; // Quests - this.izual = function () { - var izualCoords, myPosition, merc, izualPreset, timer, izual, monster, - moveAway = function (unit, range) { + this.radament = function () { + if (!Config.Rusher.Radament) { + return false; + } + + say("starting radament"); + + var i, radaCoords, rada, radaPreset, returnSpot, + moveIntoPos = function (unit, range) { var i, coordx, coordy, + coords = [], angle = Math.round(Math.atan2(me.y - unit.y, me.x - unit.x) * 180 / Math.PI), - angles = [0, 45, -45, 90, -90, 135, -135, 180]; + angles = [0, 15, -15, 30, -30, 45, -45, 60, -60, 75, -75, 90, -90, 105, -105, 120, -120, 135, -135, 150, -150, 180]; for (i = 0; i < angles.length; i += 1) { coordx = Math.round((Math.cos((angle + angles[i]) * Math.PI / 180)) * range + unit.x); @@ -996,24 +1020,166 @@ MainLoop: try { if (!(getCollision(unit.area, coordx, coordy) & 0x1)) { - return Pather.moveTo(coordx, coordy); + coords.push({ + x: coordx, + y: coordy + }); } } catch (e) { } } + if (coords.length > 0) { + coords.sort(Sort.units); + + return Pather.moveToUnit(coords[0]); + } + return false; - }, - nearbyMonsterCheck = function (range) { - var monster = getUnit(1); + }; - if (monster) { - do { - if (Attack.checkMonster(monster) && getDistance(me, monster) < range) { - return monster; + Pather.useWaypoint(48, true); + Precast.doPrecast(false); + Pather.moveToExit(49, true); + + radaPreset = getPresetUnit(49, 2, 355); + radaCoords = { + area: 49, + x: radaPreset.roomx * 5 + radaPreset.x, + y: radaPreset.roomy * 5 + radaPreset.y + }; + + moveIntoPos(radaCoords, 50); + + for (i = 0; i < 3; i += 1) { + rada = getUnit(1, 229); + + if (rada) { + break; + } + + delay(500); + } + + if (rada) { + moveIntoPos(rada, 60); + } else { + print("radament unit not found"); + } + + Attack.securePosition(me.x, me.y, 35, 3000); + Pather.makePortal(); + say("1"); + + while (!this.playerIn()) { + delay(200); + } + + Attack.kill(229); // Radament + + returnSpot = { + x: me.x, + y: me.y + }; + + say("2"); + Pickit.pickItems(); + Attack.securePosition(me.x, me.y, 30, 3000); + + while (this.playerIn()) { + delay(200); + } + + Pather.moveToUnit(returnSpot); + Pather.makePortal(); + say("all in"); + + while (!this.playerIn()) { + delay(200); + } + + while (getUnit(4, 552)) { + delay(1000); + } + + while (this.playerIn()) { + delay(200); + } + + Pather.usePortal(null, null); + + return true; + }; + + this.lamesen = function () { + if (!Config.Rusher.LamEsen) { + return false; + } + + say("starting lamesen"); + + if (!Town.goToTown() || !Pather.useWaypoint(80, true)) { + throw new Error("Lam Essen quest failed"); + } + + Precast.doPrecast(false); + + if (!Pather.moveToExit(94, true) || !Pather.moveToPreset(me.area, 2, 193)) { + throw new Error("Lam Essen quest failed"); + } + + Attack.securePosition(me.x, me.y, 30, 2000); + Pather.makePortal(); + say("1"); + + while (!this.playerIn()) { + delay(200); + } + + while (this.playerIn()) { + delay(200); + } + + Pather.usePortal(null, null); + + return true; + }; + + this.izual = function () { + if (!Config.Rusher.Izual) { + return false; + } + + say("starting izual"); + + var i, izualCoords, izual, izualPreset, returnSpot, + moveIntoPos = function (unit, range) { + var i, coordx, coordy, + coords = [], + angle = Math.round(Math.atan2(me.y - unit.y, me.x - unit.x) * 180 / Math.PI), + angles = [0, 15, -15, 30, -30, 45, -45, 60, -60, 75, -75, 90, -90, 105, -105, 120, -120, 135, -135, 150, -150, 180]; + + for (i = 0; i < angles.length; i += 1) { + coordx = Math.round((Math.cos((angle + angles[i]) * Math.PI / 180)) * range + unit.x); + coordy = Math.round((Math.sin((angle + angles[i]) * Math.PI / 180)) * range + unit.y); + + try { + if (!(getCollision(unit.area, coordx, coordy) & 0x1)) { + coords.push({ + x: coordx, + y: coordy + }); } - } while (monster.getNext()); + } catch (e) { + + } + } + + if (coords.length > 0) { + coords.sort(Sort.units); + + return Pather.moveToUnit(coords[0]); } return false; @@ -1021,6 +1187,7 @@ MainLoop: Pather.useWaypoint(106, true); Precast.doPrecast(false); + Pather.moveToExit(105, true); izualPreset = getPresetUnit(105, 1, 256); izualCoords = { @@ -1029,105 +1196,143 @@ MainLoop: y: izualPreset.roomy * 5 + izualPreset.y }; - moveAway(izualCoords, 55); + moveIntoPos(izualCoords, 50); + + for (i = 0; i < 3; i += 1) { + izual = getUnit(1, 256); + + if (izual) { + break; + } - izual = getUnit(1, 256); + delay(500); + } if (izual) { - moveAway(izual, 55); + moveIntoPos(izual, 60); + } else { + print("izual unit not found"); } - merc = me.getMerc(); - myPosition = { + returnSpot = { x: me.x, y: me.y }; - while (true) { - monster = nearbyMonsterCheck(35); + Attack.securePosition(me.x, me.y, 30, 3000); + Pather.makePortal(); + say("1"); - if (!monster) { - if (!timer) { - me.overhead("Safe Timer Start"); + while (!this.playerIn()) { + delay(200); + } - timer = getTickCount(); - } + Attack.kill(256); // Izual + Pickit.pickItems(); + say("2"); + Pather.moveToUnit(returnSpot); - if (timer && getTickCount() - timer >= 5000) { - break; - } - } else { - timer = 0; - } + while (this.playerIn()) { + delay(200); + } - izual = getUnit(1, 256); + Pather.usePortal(null, null); - if (izual && getDistance(me, izual) < 40) { - moveAway(izual, 55); + return true; + }; - myPosition = { - x: me.x, - y: me.y - }; - } + this.shenk = function () { + if (!Config.Rusher.Shenk) { + return false; + } - if (izual && getDistance(monster, izual) > 35) { - try { - Attack.kill(monster); - } catch (e) { + say("starting shenk"); - } - } else { - if (!izual || getDistance(me, izual) > 35) { - Attack.clear(15); - } - } + Pather.useWaypoint(111, true); + Precast.doPrecast(false); + Pather.moveTo(3846, 5120); + Attack.securePosition(me.x, me.y, 30, 3000); + Pather.makePortal(); + say("1"); - if (getDistance(me, myPosition) > 5 || (merc && getDistance(me, merc) > 10)) { - Pather.teleportTo(myPosition.x, myPosition.y); - } + while (!this.playerIn()) { + delay(200); + } + + Attack.kill(getLocaleString(22435)); // Shenk + Pickit.pickItems(); + Pather.moveTo(3846, 5120); + say("2"); + while (this.playerIn()) { delay(200); } + Pather.usePortal(null, null); + + return true; + }; + + this.anya = function () { + if (!Config.Rusher.Anya) { + return false; + } + + say("starting anya"); + + var anya; + + if (!Town.goToTown() || !Pather.useWaypoint(113, true)) { + throw new Error("Anya quest failed"); + } + + Precast.doPrecast(false); + + if (!Pather.moveToExit(114, true) || !Pather.moveToPreset(me.area, 2, 460)) { + throw new Error("Anya quest failed"); + } + + Attack.securePosition(me.x, me.y, 30, 2000); + + anya = getUnit(2, 558); + + if (anya) { + Pather.moveToUnit(anya); + sendPacket(1, 0x13, 4, 0x2, 4, anya.gid); // Rusher should be able to interact so quester can get the potion without entering + delay(1000 + me.ping); + me.cancel(); + } + Pather.makePortal(); say("1"); while (!this.playerIn()) { - monster = nearbyMonsterCheck(35); - izual = getUnit(1, 256); - - if (monster) { - if (izual && getDistance(monster, izual) > 35) { - try { - Attack.kill(monster); - } catch (e2) { + delay(200); + } - } - } else { - if (!izual || getDistance(me, izual) > 35) { - Attack.clear(15); - } - } - } + while (getUnit(2, 558)) { + delay(1000); + } - if (getDistance(me, myPosition) > 5 || (merc && getDistance(me, merc) > 10)) { - Pather.teleportTo(myPosition.x, myPosition.y); - } + say("2"); // Mainly for non-questers to know when to get the scroll of resistance + while (this.playerIn()) { delay(200); } - Pather.moveToUnit(izualCoords); // Temporary line until hdin attack fix is up - Attack.kill(256); // Izual Pather.usePortal(null, null); return true; }; + print("Loading RushThread"); + var i, command, current = 0, - sequence = ["andariel", "cube", "amulet", "staff", "summoner", "duriel", "travincal", "mephisto", "diablo", "ancients", "baal"]; + sequence = [ + "andariel", "radament", "cube", "amulet", "staff", "summoner", "duriel", "lamesen", + "travincal", "mephisto", "izual", "diablo", "shenk", "anya", "ancients", "baal" + ]; this.scriptEvent = function (msg) { command = msg; @@ -1140,6 +1345,7 @@ MainLoop: Pickit.init(false); Attack.init(); Storage.Init(); + CraftingSystem.buildLists(); Runewords.init(); Cubing.init(); @@ -1147,19 +1353,25 @@ MainLoop: if (command) { switch (command) { case "go": - if (current >= sequence.length) { + // End run if entire sequence is done or if Config.Rusher.LastRun is done + if (current >= sequence.length || (Config.Rusher.LastRun && current > sequence.indexOf(Config.Rusher.LastRun))) { + delay(3000); say("bye ~"); - quit(); - break; - } + while (Misc.getPlayerCount() > 1) { + delay(1000); + } + + scriptBroadcast("quit"); - say("Starting " + sequence[current]); + return true; + } try { this[sequence[current]](); } catch (sequenceError) { say(sequenceError.message); + say("2"); Town.goToTown(); } diff --git a/d2bs/kolbot/tools/ToolsThread.js b/d2bs/kolbot/tools/ToolsThread.js index 15364ed43..306d3ed24 100644 --- a/d2bs/kolbot/tools/ToolsThread.js +++ b/d2bs/kolbot/tools/ToolsThread.js @@ -4,27 +4,47 @@ * @desc several tools to help the player - potion use, chicken, Diablo clone stop, map reveal, quit with player */ +js_strict(true); + +include("json2.js"); +include("NTItemParser.dbl"); +include("OOG.js"); +include("AutoMule.js"); +include("Gambling.js"); +include("CraftingSystem.js"); +include("TorchSystem.js"); +include("MuleLogger.js"); +include("common/Attack.js"); +include("common/Cubing.js"); +include("common/CollMap.js"); +include("common/Config.js"); +include("common/Loader.js"); +include("common/Misc.js"); +include("common/Pickit.js"); +include("common/Pather.js"); +include("common/Precast.js"); +include("common/Prototypes.js"); +include("common/Runewords.js"); +include("common/Storage.js"); +include("common/Town.js"); + function main() { var i, mercHP, ironGolem, tick, merc, debugInfo = {area: 0, currScript: "no entry"}, pingTimer = [], quitFlag = false, + cloneWalked = false, + canQuit = true, timerLastDrink = []; - include("OOG.js"); - include("json2.js"); - include("automule.js"); - include("common/Attack.js"); - include("common/Config.js"); - include("common/Cubing.js"); - include("common/Pather.js"); - include("common/Prototypes.js"); - include("common/Runewords.js"); - include("common/Town.js"); - include("common/Misc.js"); print("ÿc3Start ToolsThread script"); D2Bot.init(); - Config.init(); + Config.init(false); + Pickit.init(false); + Storage.Init(); + CraftingSystem.buildLists(); + Runewords.init(); + Cubing.init(); for (i = 0; i < 5; i += 1) { timerLastDrink[i] = 0; @@ -70,14 +90,40 @@ function main() { return false; }; + this.initQuitList = function () { + var i, string, obj, + temp = []; + + for (i = 0; i < Config.QuitList.length; i += 1) { + if (FileTools.exists("data/" + Config.QuitList[i] + ".json")) { + string = Misc.fileAction("data/" + Config.QuitList[i] + ".json", 0); + + if (string) { + obj = JSON.parse(string); + + if (obj && obj.hasOwnProperty("name")) { + temp.push(obj.name); + } + } + } + } + + Config.QuitList = temp.slice(0); + }; + this.getPotion = function (pottype, type) { var i, items = me.getItems(); - if (!items) { + if (!items || items.length === 0) { return false; } + // Get highest id = highest potion first + items.sort(function (a, b) { + return b.classid - a.classid; + }); + for (i = 0; i < items.length; i += 1) { if (type < 3 && items[i].mode === 0 && items[i].location === 3 && items[i].itemType === pottype) { print("ÿc2Drinking potion from inventory."); @@ -95,20 +141,23 @@ function main() { this.togglePause = function () { var i, script, - scripts = ["default.dbj", "tools/townchicken.js", "tools/antihostile.js", "tools/party.js", "tools/flashthread.js", "tools/rushthread.js"]; + scripts = ["default.dbj", "tools/townchicken.js", "tools/antihostile.js", "tools/party.js", "tools/rushthread.js"]; for (i = 0; i < scripts.length; i += 1) { script = getScript(scripts[i]); if (script) { if (script.running) { - if (script.name === "default.dbj") { + if (i === 0) { // default.dbj print("ÿc1Pausing."); } - script.pause(); + // don't pause townchicken during clone walk + if (scripts[i] !== "tools/townchicken.js" || !cloneWalked) { + script.pause(); + } } else { - if (script.name === "default.dbj") { + if (i === 0) { // default.dbj print("ÿc2Resuming."); } @@ -123,7 +172,7 @@ function main() { this.stopDefault = function () { var script = getScript("default.dbj"); - if (script) { + if (script && script.running) { script.stop(); } @@ -149,7 +198,7 @@ function main() { break; case 2: case 4: - if (timerLastDrink[type] && (tNow - timerLastDrink[type] < 500)) { // small delay for juvs just to prevent using more at once + if (timerLastDrink[type] && (tNow - timerLastDrink[type] < 300)) { // small delay for juvs just to prevent using more at once return false; } @@ -195,7 +244,7 @@ function main() { try { clickItem(2, potion); } catch (e) { - this.drinkPotion(type); // Recursive check - we better drink the damn potion + print("Couldn't give the potion to merc."); } } @@ -239,12 +288,17 @@ function main() { }; this.checkVipers = function () { - var monster = getUnit(1, 597); + var owner, + monster = getUnit(1, 597); if (monster) { do { - if (monster.getState(96) && monster.getParent().name !== me.name) { - return true; + if (monster.getState(96)) { + owner = monster.getParent(); + + if (owner && owner.name !== me.name) { + return true; + } } } while (monster.getNext()); } @@ -253,29 +307,36 @@ function main() { }; this.getIronGolem = function () { - var golem = getUnit(1, "iron golem"); + var owner, + golem = getUnit(1, 291); - if (!golem) { - return false; - } + if (golem) { + do { + owner = golem.getParent(); - do { - if (golem.getParent().name === me.name) { - return golem; - } - } while (golem.getNext()); + if (owner && owner.name === me.name) { + return copyUnit(golem); + } + } while (golem.getNext()); + } return false; }; - this.revealArea = function (area) { - var room = getRoom(area); + this.getNearestPreset = function () { + var i, unit, dist, id; - do { - if (room instanceof Room && room.area === area) { - room.reveal(); + unit = getPresetUnits(me.area); + dist = 99; + + for (i = 0; i < unit.length; i += 1) { + if (getDistance(me, unit[i].roomx * 5 + unit[i].x, unit[i].roomy * 5 + unit[i].y) < dist) { + dist = getDistance(me, unit[i].roomx * 5 + unit[i].x, unit[i].roomy * 5 + unit[i].y); + id = unit[i].type + " " + unit[i].id; } - } while (room.getNext()); + } + + return id || ""; }; // Event functions @@ -287,27 +348,31 @@ function main() { break; case 123: // F12 key me.overhead("Revealing " + Pather.getAreaName(me.area)); - this.revealArea(me.area); + revealLevel(true); break; case 107: // Numpad + showConsole(); - print("ÿc4MF: ÿc0" + me.getStat(80) + " ÿc4GF: ÿc0" + me.getStat(79) + " ÿc1FR: ÿc0" + me.getStat(39) - + " ÿc3CR: ÿc0" + me.getStat(43) + " ÿc9LR: ÿc0" + me.getStat(41) + " ÿc2PR: ÿc0" + me.getStat(45)); + print("ÿc4MF: ÿc0" + me.getStat(80) + " ÿc4GF: ÿc0" + me.getStat(79) + " ÿc1FR: ÿc0" + me.getStat(39) + + " ÿc3CR: ÿc0" + me.getStat(43) + " ÿc9LR: ÿc0" + me.getStat(41) + " ÿc2PR: ÿc0" + me.getStat(45)); break; case 101: // numpad 5 if (AutoMule.getInfo() && AutoMule.getInfo().hasOwnProperty("muleInfo")) { - print("ÿc2Mule triggered"); - scriptBroadcast("mule"); - this.exit(); + if (AutoMule.getMuleItems().length > 0) { + print("ÿc2Mule triggered"); + scriptBroadcast("mule"); + this.exit(); + } else { + me.overhead("No items to mule."); + } } else { me.overhead("Profile not enabled for muling."); } break; - case 102: - Misc.spy(me.name); + case 102: // Numpad 6 + MuleLogger.logChar(); break; case 109: // Numpad - @@ -318,35 +383,20 @@ function main() { say("/fps"); break; - case 100: // numpad 4 - get nearest preset unit id + case 105: // numpad 9 - get nearest preset unit id print(this.getNearestPreset()); break; } }; - this.getNearestPreset = function () { - var i, unit, dist, id; - - unit = getPresetUnits(me.area); - dist = 99; - - for (i = 0; i < unit.length; i += 1) { - if (getDistance(me, unit[i].roomx * 5 + unit[i].x, unit[i].roomy * 5 + unit[i].y) < dist) { - dist = getDistance(me, unit[i].roomx * 5 + unit[i].x, unit[i].roomy * 5 + unit[i].y); - id = unit[i].type + " " + unit[i].id; - } - } - - return id || ""; - }; - this.gameEvent = function (mode, param1, param2, name1, name2) { switch (mode) { case 0x00: // "%Name1(%Name2) dropped due to time out." case 0x01: // "%Name1(%Name2) dropped due to errors." case 0x03: // "%Name1(%Name2) left our world. Diablo's minions weaken." - if (Config.QuitList.indexOf(name1) > -1) { + if ((typeof Config.QuitList === "string" && Config.QuitList.toLowerCase() === "any") || + (Config.QuitList instanceof Array && Config.QuitList.indexOf(name1) > -1)) { print(name1 + (mode === 0 ? " timed out" : " left")); quitFlag = true; @@ -370,15 +420,34 @@ function main() { break; case 0x11: // "%Param1 Stones of Jordan Sold to Merchants" - if (Config.SoJWaitTime) { + if (Config.DCloneQuit === 2) { + D2Bot.printToConsole("SoJ sold in game. Leaving."); + + quitFlag = true; + + break; + } + + if (Config.SoJWaitTime && me.gametype === 1) { // only do this in expansion D2Bot.printToConsole(param1 + " Stones of Jordan Sold to Merchants on IP " + me.gameserverip.split(".")[3], 7); - scriptBroadcast("soj"); + Messaging.sendToScript("default.dbj", "soj"); } break; case 0x12: // "Diablo Walks the Earth" - if (Config.StopOnDClone) { + if (Config.DCloneQuit > 0) { + D2Bot.printToConsole("Diablo walked in game. Leaving."); + + quitFlag = true; + + break; + } + + if (Config.StopOnDClone && me.gametype === 1) { // only do this in expansion D2Bot.printToConsole("Diablo Walks the Earth", 7); + + cloneWalked = true; + this.togglePause(); Town.goToTown(); showConsole(); @@ -397,8 +466,12 @@ function main() { this.scriptEvent = function (msg) { var obj; - + switch (msg) { + case "toggleQuitlist": + canQuit = !canQuit; + + break; case "quit": quitFlag = true; @@ -420,6 +493,7 @@ function main() { } //D2Bot.store(JSON.stringify(debugInfo)); + DataFile.updateStats("debugInfo", JSON.stringify(debugInfo)); } break; @@ -433,6 +507,7 @@ function main() { addEventListener("keyup", this.keyEvent); addEventListener("gameevent", this.gameEvent); addEventListener("scriptmsg", this.scriptEvent); + addEventListener("gamepacket", Events.gamePacket); // Load Fastmod Packet.changeStat(105, Config.FCR); @@ -440,6 +515,10 @@ function main() { Packet.changeStat(102, Config.FBR); Packet.changeStat(93, Config.IAS); + if (Config.QuitListMode > 0) { + this.initQuitList(); + } + // Start while (true) { try { @@ -535,7 +614,7 @@ function main() { quitFlag = true; } - if (quitFlag) { + if (quitFlag && canQuit) { print("ÿc8Run duration ÿc2" + ((getTickCount() - me.gamestarttime) / 1000)); if (Config.LogExperience) { @@ -547,13 +626,16 @@ function main() { break; } - - /*if (debugInfo.area !== me.area) { - debugInfo.area = me.area; - D2Bot.store(JSON.stringify(debugInfo)); - }*/ + if (debugInfo.area !== Pather.getAreaName(me.area)) { + debugInfo.area = Pather.getAreaName(me.area); + + //D2Bot.store(JSON.stringify(debugInfo)); + DataFile.updateStats("debugInfo", JSON.stringify(debugInfo)); + } delay(20); } + + return true; } \ No newline at end of file diff --git a/d2bs/kolbot/tools/TownChicken.js b/d2bs/kolbot/tools/TownChicken.js index 653af6afd..54e0009d5 100644 --- a/d2bs/kolbot/tools/TownChicken.js +++ b/d2bs/kolbot/tools/TownChicken.js @@ -10,6 +10,7 @@ include("json2.js"); include("NTItemParser.dbl"); include("OOG.js"); include("Gambling.js"); +include("CraftingSystem.js"); include("common/Attack.js"); include("common/Cubing.js"); include("common/Config.js"); @@ -29,24 +30,27 @@ function main() { this.togglePause = function () { var i, script, - scripts = ["default.dbj", "tools/antihostile.js", "tools/rushthread.js"]; + scripts = ["default.dbj", "tools/antihostile.js", "tools/rushthread.js", "tools/CloneKilla.js"]; for (i = 0; i < scripts.length; i += 1) { script = getScript(scripts[i]); if (script) { if (script.running) { - if (script.name === "default.dbj") { + if (i === 0) { // default.dbj print("ÿc1Pausing."); } script.pause(); } else { - if (script.name === "default.dbj") { - print("ÿc2Resuming."); + if (i === 0) { // default.dbj + if (!getScript("tools/clonekilla.js")) { // resume only if clonekilla isn't running + print("ÿc2Resuming."); + script.resume(); + } + } else { + script.resume(); } - - script.resume(); } } } @@ -63,8 +67,7 @@ function main() { townCheck = true; } } - } - ); + }); // Init config and attacks D2Bot.init(); @@ -72,13 +75,14 @@ function main() { Pickit.init(); Attack.init(); Storage.Init(); + CraftingSystem.buildLists(); Runewords.init(); Cubing.init(); while (true) { if (!me.inTown && (townCheck || (Config.TownHP > 0 && me.hp < Math.floor(me.hpmax * Config.TownHP / 100)) || - (Config.TownMP > 0 && me.hp < Math.floor(me.hpmax * Config.TownMP / 100)))) { + (Config.TownMP > 0 && me.mp < Math.floor(me.mpmax * Config.TownMP / 100)))) { this.togglePause(); while (!me.gameReady) { @@ -102,4 +106,4 @@ function main() { delay(50); } -} +} \ No newline at end of file diff --git a/d2bs/libnspr4.dll b/d2bs/libnspr4.dll deleted file mode 100644 index 3ac89e074..000000000 Binary files a/d2bs/libnspr4.dll and /dev/null differ