diff --git a/D2Bot.exe b/D2Bot.exe index 20bfc6163..42316db2d 100644 Binary files a/D2Bot.exe and b/D2Bot.exe differ diff --git a/Readme.txt b/Readme.txt index 1dc60b472..25f5944d9 100644 --- a/Readme.txt +++ b/Readme.txt @@ -1,187 +1,11 @@ -DDDDDDDDDDDDD 222222222222222 BBBBBBBBBBBBBBBBB OOOOOOOOO TTTTTTTTTTTTTTTTTTTTTTT -D::::::::::::DDD 2:::::::::::::::22 B::::::::::::::::B OO:::::::::OO T:::::::::::::::::::::T ###### ###### -D:::::::::::::::DD 2::::::222222:::::2 B::::::BBBBBB:::::B OO:::::::::::::OO T:::::::::::::::::::::T #::::# #::::# -DDD:::::DDDDD:::::D 2222222 2:::::2 BB:::::B B:::::BO:::::::OOO:::::::OT:::::TT:::::::TT:::::T #::::# #::::# - D:::::D D:::::D 2:::::2 B::::B B:::::BO::::::O O::::::OTTTTTT T:::::T TTTTTT######::::######::::###### - D:::::D D:::::D 2:::::2 B::::B B:::::BO:::::O O:::::O T:::::T #::::::::::::::::::::::::# - D:::::D D:::::D 2222::::2 B::::BBBBBB:::::B O:::::O O:::::O T:::::T ######::::######::::###### - D:::::D D:::::D 22222::::::22 B:::::::::::::BB O:::::O O:::::O T:::::T #::::# #::::# - D:::::D D:::::D 22::::::::222 B::::BBBBBB:::::B O:::::O O:::::O T:::::T #::::# #::::# - D:::::D D:::::D 2:::::22222 B::::B B:::::BO:::::O O:::::O T:::::T ######::::######::::###### - D:::::D D:::::D2:::::2 B::::B B:::::BO:::::O O:::::O T:::::T #::::::::::::::::::::::::# - D:::::D D:::::D 2:::::2 B::::B B:::::BO::::::O O::::::O T:::::T ######::::######::::###### -DDD:::::DDDDD:::::D 2:::::2 222222BB:::::BBBBBB::::::BO:::::::OOO:::::::O TT:::::::TT #::::# #::::# -D:::::::::::::::DD 2::::::2222222:::::2B:::::::::::::::::B OO:::::::::::::OO T:::::::::T #::::# #::::# -D::::::::::::DDD 2::::::::::::::::::2B::::::::::::::::B OO:::::::::OO T:::::::::T ###### ###### -DDDDDDDDDDDDD 22222222222222222222BBBBBBBBBBBBBBBBB OOOOOOOOO TTTTTTTTTTT - _____ ____ _____ _______ _____ ______ ______ _____ -| __ \___ \ / ____|__ __| __ \ / __ \ \ / /___ \| __ \ -| | | |__) | (___ | | | |__) | | | \ \_/ / __) | |__) | -| | | |__ < \___ \ | | | _ /| | | |\ / |__ <| _ / -| |__| |__) |____) | | | | | \ \| |__| | | | ___) | | \ \ -|_____/____/|_____/ |_| |_| \_\\____/ |_| |____/|_| \_\ +This is the MASTER (also known as TRUNK) branch. -DISCLAIMER: -D2BOTSHARP, A GAME MANAGER FROM D2BOT, ALL RIGHTS RESERVED -BY USING THIS SOFTWARE, YOU AGREE TO ITS END USER LICENSE AGREEMENT +The package contains 3 distinct components: +D2BS - core +D2Bot# - manager +kolbot - script library -END-USER LICENSE AGREEMENT FOR D2BOTSHARP IMPORTANT PLEASE READ THE TERMS AND CONDITIONS OF THIS LICENSE AGREEMENT CAREFULLY BEFORE CONTINUING WITH THIS PROGRAM INSTALL: D2BOT End-User License Agreement ("EULA") is a legal agreement between you (either an individual or a single entity) and D2BOT. for the D2BOT software product(s) identified above which may include associated software components, media, printed materials, and "online" or electronic documentation ("SOFTWARE PRODUCT"). By installing, copying, or otherwise using the SOFTWARE PRODUCT, you agree to be bound by the terms of this EULA. This license agreement represents the entire agreement concerning the program between you and D2BOT, (referred to as "licenser"), and it supersedes any prior proposal, representation, or understanding between the parties. If you do not agree to the terms of this EULA, do not install or use the SOFTWARE PRODUCT. +If you want to contribute to kolbot code, make sure you use JSLint for final polish. +If you want to contribute to d2bs/d2bot#, come to irc.synirc.net/d2bs and ask around. -The SOFTWARE PRODUCT is protected by copyright laws and international copyright treaties, as well as other intellectual property laws and treaties. The SOFTWARE PRODUCT is licensed, not sold. - -1. GRANT OF LICENSE. -The SOFTWARE PRODUCT is licensed as follows: -(a) Installation and Use. -D2BOT grants you the right to install and use copies of the SOFTWARE PRODUCT on your computer running a validly licensed copy of the operating system for which the SOFTWARE PRODUCT was designed [e.g., Windows 95, Windows NT, Windows 98, Windows 2000, Windows 2003, Windows XP, Windows ME, Windows Vista]. -(b) Backup Copies. -You may also make copies of the SOFTWARE PRODUCT as may be necessary for backup and archival purposes. - -2. DESCRIPTION OF OTHER RIGHTS AND LIMITATIONS. -(a) Maintenance of Copyright Notices. -You must not remove or alter any copyright notices on any and all copies of the SOFTWARE PRODUCT. -(b) Distribution. -You may not distribute registered copies of the SOFTWARE PRODUCT to third parties. Evaluation versions available for download from D2BOT's websites may be freely distributed. -(c) Prohibition on Reverse Engineering, Decompilation, and Disassembly. -You may not reverse engineer, decompile, or disassemble the SOFTWARE PRODUCT, except and only to the extent that such activity is expressly permitted by applicable law notwithstanding this limitation. -(d) Rental. -You may not rent, lease, or lend the SOFTWARE PRODUCT. -(e) Support Services. -D2BOT may provide you with support services related to the SOFTWARE PRODUCT ("Support Services"). Any supplemental software code provided to you as part of the Support Services shall be considered part of the SOFTWARE PRODUCT and subject to the terms and conditions of this EULA. -(f) Compliance with Applicable Laws. -You must comply with all applicable laws regarding use of the SOFTWARE PRODUCT. - -3. TERMINATION -Without prejudice to any other rights, D2BOT may terminate this EULA if you fail to comply with the terms and conditions of this EULA. In such event, you must destroy all copies of the SOFTWARE PRODUCT in your possession. - -4. COPYRIGHT -All title, including but not limited to copyrights, in and to the SOFTWARE PRODUCT and any copies thereof are owned by D2BOT or its suppliers. All title and intellectual property rights in and to the content which may be accessed through use of the SOFTWARE PRODUCT is the property of the respective content owner and may be protected by applicable copyright or other intellectual property laws and treaties. This EULA grants you no rights to use such content. All rights not expressly granted are reserved by D2BOT. - -5. NO WARRANTIES -D2BOT expressly disclaims any warranty for the SOFTWARE PRODUCT. The SOFTWARE PRODUCT is provided 'As Is' without any express or implied warranty of any kind, including but not limited to any warranties of merchantability, noninfringement, or fitness of a particular purpose. D2BOT does not warrant or assume responsibility for the accuracy or completeness of any information, text, graphics, links or other items contained within the SOFTWARE PRODUCT. D2BOT makes no warranties respecting any harm that may be caused by the transmission of a computer virus, worm, time bomb, logic bomb, or other such computer program. D2BOT further expressly disclaims any warranty or representation to Authorized Users or to any third party. - -6. LIMITATION OF LIABILITY -In no event shall D2BOT be liable for any damages (including, without limitation, lost profits, business interruption, or lost information) rising out of 'Authorized Users' use of or inability to use the SOFTWARE PRODUCT, even if D2BOT has been advised of the possibility of such damages. In no event will D2BOT be liable for loss of data or for indirect, special, incidental, consequential (including lost profit), or other damages based in contract, tort or otherwise. D2BOT shall have no liability with respect to the content of the SOFTWARE PRODUCT or any part thereof, including but not limited to errors or omissions contained therein, libel, infringements of rights of publicity, privacy, trademark rights, business interruption, personal injury, loss of privacy, moral rights or the disclosure of confidential information. - - - _ _ _____ ___________ _____ ___ ___ ___ _ _ _ _ ___ _ -| | | / ___| ___| ___ \/ ___| | \/ | / _ \ | \ | | | | |/ _ \ | | -| | | \ `--.| |__ | |_/ /\ `--. | . . |/ /_\ \| \| | | | / /_\ \| | -| | | |`--. \ __|| / `--. \ | |\/| || _ || . ` | | | | _ || | -| |_| /\__/ / |___| |\ \ /\__/ / | | | || | | || |\ | |_| | | | || |____ - \___/\____/\____/\_| \_|\____/ \_| |_/\_| |_/\_| \_/\___/\_| |_/\_____/ - -Getting Started: - -Make sure your directory is setup accordingly. - -.../D2Bot dir/ -in the initial directory these files must exist -Folder: D2BS -File: D2Bot.exe -File: profile.ini -File: d2bot.log - -.../D2Bot dir/D2BS/ -in your D2BS folder, make sure the following exist -File: D2BS.dll -File: D2M.dll -Folder: ex: kolbot - -.../D2Bot dir/D2BS/scripts.../ -in your initial scirpts folder you must have -Folder: data <--- THIS IS MANDATORY! -File: D2BotLead.dbj -File: D2BotFollow.dbj -File: Any other starters you want - - -D2BotSharp API (available from js) - -the D2Bot.js file holds the current functions available from js to D2Bot -they include functions that --write to console --write to item log --increment various values --receive game data --set status - -D2BotSharp Usage -Some functions you can call from the console ->>start # // this will start a particular profile based on name ->>stop # // this will stop a particular profile based on name ->>start all // this will start all profiles ->>stop all // this will stop all profiles ->>add // this will create new profile for you to fill out ->>del # // this will delete a profile ->>send #1 msg #2 // this will send a string message to profile designated by #1 and will also send an id designated by #2 -You can use >>send to add your own api to d2bot#, for example, with a windows message handler from scripts you can receive any command from d2bot# - -Buttons -Start // This will start a highlighted (selected) profile, you may select multiple profiles and it will start them -Stop // This will stop a highlighted (selected) profile, you may select multiple profiles and it will stop them -Edit // This will open a profile editor for already created profiles -Add // This will open a a new profile for you to edit -Duplicate // This will create a copy of a profile -Delete // This will delete a profile -Save // this will save the current run info on all the profiles - -Right Click Profile -Increment CDKEY // manually go to next key or skip current key - - -Note: all buttons are responsive to multiple profile selections, you do not have to select 1 at a time. - -Task Bar -File: Start ALL // this will start all profiles -File: Stop ALL // this will stop all profiles -File: Save // this will save the current run info on all profiles - -Tools: Start Hidden // this will start d2 completely hidden, you won't even notice that you are botting! -Tools: Hide All // this will hide all currently visible d2's started from d2bot# -Tools: Show All // this will un-hide all d2's started form d2bot# -Tools: Edit // Same as above -Tools: Add // Save as above - -d2bot.log -This file will hold information on disabled cdkeys, inuse cdkeys and timestamp when they were used - -How to reorder your profiles? -Drag and drop them to where you want them to go! - -How to add cdkeys: -In profile editor, type the cdkeys as shown: -example.mpq -exmaple2.mpq -exmaple3.mpq -... -etc - -Runs/Key This is how many runs before d2 will load a new cdkey, if you are not using any additional cdkeys, set it to -1 - -Parameters For all profiles, you should use -w (unless you want to bot / load in full screen). -Other Flags include: --direct -txt --ns --lq --skiptobnet - -ex: -w -ns -lq -note: do not use -title and do not use -cachefix - -Explanation of Profile Editor: -Name: this is the name of your profile -Account: account of your bot -Password: pass of your bot account -Character: the character you want to bot (case sensitive) -Game Name: prefix for game, if you are a leecher it does not matter -Game Pass: game password, if you are a leecher it does not matter -Difficulty: Hell, Nightmare, Norm -Mode: Battlenet Singleplayer -Entry Script: This is your starter file, unless you are using something custom, choose D2BotLead or D2BotFollow -NOTE: Entry Script also determines your scirpts folder, so if you are using yamb, you need to pick the starter from your yamb directory -Diablo Path: Choose any diablo 2 file, this can be game.exe game1.exe etc... you can use multiple game.exe's from the same d2 folder (incase you are using proxycap) - -How to Resize: -drag and drop corners - -Note: You also need a data folder in your scripts directory, this will hold game info for your characters \ No newline at end of file +JSLint options for kolbot code: http://pastebin.com/4t5J9QpL \ No newline at end of file diff --git a/d2bs/D2BS.dll b/d2bs/D2BS.dll index 613145cef..3466ff570 100644 Binary files a/d2bs/D2BS.dll and b/d2bs/D2BS.dll differ diff --git a/d2bs/D2BS.exe b/d2bs/D2BS.exe deleted file mode 100644 index 9aa5a16b9..000000000 Binary files a/d2bs/D2BS.exe and /dev/null differ diff --git a/d2bs/D2BS.pdb b/d2bs/D2BS.pdb new file mode 100644 index 000000000..8bcf4d006 Binary files /dev/null and b/d2bs/D2BS.pdb differ diff --git a/d2bs/D2M.dll b/d2bs/D2M.dll deleted file mode 100644 index 2fc5a5be9..000000000 Binary files a/d2bs/D2M.dll and /dev/null 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/D2BotBlank.dbj b/d2bs/kolbot/D2BotBlank.dbj index 175f538e9..7cc821e67 100644 --- a/d2bs/kolbot/D2BotBlank.dbj +++ b/d2bs/kolbot/D2BotBlank.dbj @@ -1,45 +1,64 @@ // Blank starter used for testin - -const D2BOT_JOIN = 1; -const D2BOT_GAMEINFO = 2; -const D2BOT_REQUESTGAME = 3; - -var isUp = "no"; - function main() { include("json2.js"); include("OOG.js"); - - addEventListener('copydata', RecieveCopyData); + include("common/misc.js"); + + var handle, + isUp = "no"; + + this.copyDataEvent = function (mode, msg) { + var obj; + + switch (msg) { + case "Handle": + handle = mode; + + break; + } + + switch (mode) { + case 3: // request game + obj = JSON.parse(msg); + + if (me.gameReady) { + D2Bot.joinMe(obj.profile, me.gamename.toLowerCase(), "", me.gamepassword.toLowerCase(), isUp); + } + + break; + case 4: + // Heartbeat ping + if (msg === "pingreq") { + sendCopyData(null, me.windowtitle, 4, "pingrep"); + } + + break; + } + }; + + + addEventListener('copydata', this.copyDataEvent); + + while (!handle) { + delay(100); + } + + DataFile.updateStats("handle", handle); + delay(500); + D2Bot.init(); + load("tools/heartbeat.js"); if (!FileTools.exists("data/" + me.profile + ".json")) { DataFile.create(); } - + while (true) { if (me.ingame) { - if (isUp === "no") { - isUp = "yes"; - } + isUp = "yes"; } else { isUp = "no"; } - + delay(1000); } -} - -function RecieveCopyData(msgID, msg){ - switch(msgID) { - case D2BOT_GAMEINFO: - print("Recieved Game Info"); - [gameName, gamePass, difficulty] = msg.split('/'); - break; - case D2BOT_JOIN: - [nextGame, gamePass, isUp] = msg.split('/'); - break; - case D2BOT_REQUESTGAME: - D2Bot.joinMe(msg, me.gamename, "", me.gamepassword, isUp); - break; - } } \ No newline at end of file diff --git a/d2bs/kolbot/D2BotChannel.dbj b/d2bs/kolbot/D2BotChannel.dbj index d2674d9cc..8fc575a42 100644 --- a/d2bs/kolbot/D2BotChannel.dbj +++ b/d2bs/kolbot/D2BotChannel.dbj @@ -4,50 +4,130 @@ var StarterConfig = { ChatActionsDelay: 2, // Seconds to wait in lobby before entering a channel // D2BotChannel settings - Games: [], // List of games to look for. Example: Games: ["some baal-", "chaos run-"], - Passwords: [], // List of game passwords. Each array in Games array should have a matching element in Passwords. Use "" for blank pw. + Games: [""], // List of games to look for. Example: Games: ["some baal-", "chaos run-"], + Passwords: [""], // List of game passwords. Each array in Games array should have a matching element in Passwords. Use "" for blank pw. JoinDelay: 5, // Seconds to wait between announcement and clicking join FriendListQuery: 0, // Seconds between "/f l" retries. 0 = disable - SwitchKeys: true, // Set to true to switch keys when they're in use, banned or after realm down SwitchKeyDelay: 0, // Seconds to wait before switching a used/banned key or after realm down + SkipMutedKey: true, + MutedKeyTrigger: "Your account has had all chat privileges suspended.", + CrashDelay: 60, // Seconds to wait after a d2 window crash RealmDownDelay: 10, // 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. SwitchKeys overrides this! 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 + GameDoesNotExistTimeout: 5 // Seconds to wait before cancelling the 'Game does not exist.' screen }; +// Advanced config - you don't have to edit this unless you need some of the features provided +var AdvancedConfig = { + /* Features: Override channel for each profile, Override join delay for each profile + + * Format *: + "Profile Name": {JoinDelay: number_of_seconds} + or + "Profile Name": {JoinChannel: "channel name"} + or + "Profile Name": {JoinChannel: "channel name", JoinDelay: number_of_seconds} + + * Example * (don't edit this - it's just an example): + + "MyProfile1": {JoinDelay: 3}, + "MyProfile2": {JoinChannel: "some channel"}, + "MyProfile3": {JoinChannel: "some other channel", JoinDelay: 11} + "MyProfile4": {AnnounceGames: true, AnnounceMessage: "Joining game"} // announce game you are joining + */ + + // Put your lines under this one. Multiple entries are separated by commas. No comma after the last one. + + "Test": { + JoinChannel: "op nnqry", + JoinDelay: 3, + AnnounceGames: true, + AnnounceMessage: "Joining game" // output: Joining game Baals-23 + } +}; // No touchy! include("json2.js"); include("OOG.js"); +include("automule.js"); +include("gambling.js"); +include("torchsystem.js"); +include("common/misc.js"); -var lastGameStatus = "ready", - nextGameMake = 0, - inGameAt = 0, - chatActionsDone = false, - lastGameFailed = false, - connectFail = false, +var gameStart, handle, ingame, firstLogin, useChat, + connectFail, chatActionsDone, gameInfo, gameCount = DataFile.getStats().runs + 1, - gamePass = "", - gameName = "", - oldGame = "", - gameStart, - isUp = "no", channelTick = getTickCount(), - inGame = false, + lastGameStatus = "ready", + fListTick = 0, retry = 0, - fListTick = 0; + badGames = [], + joinInfo = { + gameName: "", + gamePass: "", + oldGame: "", + inGame: false + }; if (!FileTools.exists("data/" + me.profile + ".json")) { DataFile.create(); } +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) { + break; + } + + if (gameInfo) { + obj = JSON.parse(msg); + + D2Bot.joinMe(obj.profile, me.gamename || "", "", me.gamepassword || "", me.gameReady ? "yes" : "no"); + } + + break; + case 4: + // Heartbeat ping + if (msg === "pingreq") { + sendCopyData(null, me.windowtitle, 4, "pingrep"); + } + + break; + } +} + function timeoutDelay(text, time) { var endTime = getTickCount() + time; @@ -67,36 +147,125 @@ function locationTimeout(time, location) { 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 "getMuleMode": + if (AutoMule.torchAnniCheck === 2) { + scriptBroadcast("2"); + } else if (AutoMule.torchAnniCheck === 1) { + scriptBroadcast("1"); + } else if (AutoMule.check) { + scriptBroadcast("0"); + } + + 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 main() { - delay(rand(1, 2) * 1000); + addEventListener('copydata', ReceiveCopyData); + addEventListener('scriptmsg', ScriptMsgEvent); + + while (!handle) { + delay(100); + } + + DataFile.updateStats("handle", handle); + D2Bot.init(); + load("tools/heartbeat.js"); + + while (!gameInfo) { + D2Bot.requestGameInfo(); + delay(500); + } + + 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 - isUp = "yes"; - - if (!inGame) { - if (me.gamepassword.toLowerCase() !== gamePass.toLowerCase()) { - print("leaving game"); - quit(); - } + joinInfo.inGame = true; + if (!ingame) { print("Updating Status"); - D2Bot.updateStatus("Game: " + me.gamename); + //D2Bot.updateStatus("Game: " + me.gamename); - oldGame = me.gamename; + badGames.push(joinInfo.gameName); + joinInfo.oldGame = me.gamename; lastGameStatus = "ingame"; - inGame = true; + ingame = true; gameStart = getTickCount(); DataFile.updateStats("runs", gameCount); } + + D2Bot.updateStatus("Game: " + me.gamename + timer(gameStart)); } delay(1000); } - isUp = "no"; + joinInfo.inGame = false; locationAction(getLocation()); delay(1000); @@ -112,41 +281,88 @@ MainSwitch: break; case 1: // Lobby D2Bot.updateStatus("Lobby"); + + if (!firstLogin) { + firstLogin = true; + } + 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 (inGame) { + if (ingame) { + AutoMule.outOfGameCheck(); + TorchSystem.outOfGameCheck(); + Gambling.outOfGameCheck(); print("updating runs"); D2Bot.updateRuns(); gameCount += 1; lastGameStatus = "ready"; - inGame = false; + ingame = false; retry = 0; } - if (!chatActionsDone || getTickCount() - channelTick >= 120e3) { - chatActionsDone = true; - channelTick = getTickCount(); + // Muted key handler + fullText = ""; + lines = ControlAction.getText(4, 28, 410, 354, 298); + + if (!lines) { + break; + } + fullText = lines.join(" ").replace(/\s+/g, " "); + + if (fullText.match(StarterConfig.MutedKeyTrigger.replace(/\s+/g, " "), "gi")) { + D2Bot.printToConsole(gameInfo.mpq + " is muted.", 6); + + ControlAction.mutedKey = true; + + if (StarterConfig.SkipMutedKey) { + if (gameInfo.switchKeys) { + timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + } + } + + if (!ControlAction.mutedKey && (!chatActionsDone || getTickCount() - channelTick >= 120e3)) { if (StarterConfig.JoinChannel !== "") { - timeoutDelay("Chat delay", StarterConfig.ChatActionsDelay * 1e3); - say("/j " + StarterConfig.JoinChannel); - delay(1000); + if (typeof AdvancedConfig[me.profile] === "object" && typeof AdvancedConfig[me.profile].JoinChannel === "string") { + joinInfo.joinChannel = AdvancedConfig[me.profile].JoinChannel; + } else { + joinInfo.joinChannel = StarterConfig.JoinChannel; + } + + if (joinInfo.joinChannel) { + if (ControlAction.joinChannel(joinInfo.joinChannel)) { + useChat = true; + } else { + print("Unable to join channel, chat messages disabled."); + + useChat = false; + } + } } - if (StarterConfig.FirstJoinMessage !== "") { - say(StarterConfig.FirstJoinMessage); + if (StarterConfig.FirstJoinMessage !== "" && !chatActionsDone) { // Added !chatActionsDone condition to prevent spam + timeoutDelay("Chat delay", StarterConfig.ChatActionsDelay * 1e3); + sayMsg(StarterConfig.FirstJoinMessage); delay(500); } + + chatActionsDone = true; + channelTick = getTickCount(); } if (StarterConfig.FriendListQuery > 0 && getTickCount() - fListTick >= StarterConfig.FriendListQuery * 1000) { @@ -155,17 +371,58 @@ MainSwitch: fListTick = getTickCount(); } - if (lastGameStatus === "pending") { + 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; - print("game joining failed " + retry); + D2Bot.updateRuns(); + + if (retry < 3) { + ControlAction.click(6, 652, 469, 120, 20); + + break MainSwitch; + } + + break; + case "DNE": // Game didn't exist + retry += 1; + + break; + case "FULL": // Game is full + retry = 3; + + break; } if (retry >= 3) { - print("reset game"); + //print("reset game"); + D2Bot.printToConsole("Failed to join " + joinInfo.gameName + ". Aborting."); + badGames.push(joinInfo.gameName); lastGameStatus = "ready"; - oldGame = gameName; + joinInfo.oldGame = joinInfo.gameName; retry = 0; } @@ -180,14 +437,14 @@ MainSwitch: MainLoop: for (n = 0; n < StarterConfig.Games.length; n += 1) { - regex = new RegExp("\\W*" + StarterConfig.Games[n].toLowerCase() + "\\d*", "gi"); - gameName = fullText.match(regex); + regex = new RegExp("\\W+" + StarterConfig.Games[n].toLowerCase() + "\\d+", "gi"); + joinInfo.gameName = fullText.match(regex); - if (gameName) { - gameName = gameName[gameName.length - 1].toString().replace(/^\W*/, ""); // use last match and trim it - gamePass = StarterConfig.Passwords[n]; + if (joinInfo.gameName) { + joinInfo.gameName = joinInfo.gameName[joinInfo.gameName.length - 1].toString().replace(/^\W*/, ""); // use last match and trim it + joinInfo.gamePass = StarterConfig.Passwords[n] || ""; - if (gameName !== oldGame) { + if (joinInfo.gameName && joinInfo.gameName !== joinInfo.oldGame && badGames.indexOf(joinInfo.gameName) === -1) { ControlAction.click(6, 652, 469, 120, 20); break MainLoop; @@ -199,15 +456,34 @@ MainLoop: case 4: // Create Game break; case 5: // Join Game + if (joinInfo.oldGame === joinInfo.gameName || badGames.indexOf(joinInfo.gameName) > -1) { + ControlAction.click(6, 433, 433, 96, 32); + } + D2Bot.updateStatus("Join Game"); - if (gameName !== "") { - if (StarterConfig.JoinDelay) { - delay(StarterConfig.JoinDelay * 1000); + if (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); + } + + if (retry === 0 || lastGameStatus === "pending") { // Only delay on first join - the rest is handled by GameDoesNotExistTimeout. Any other case is instant fail (ie. full game). + if (typeof AdvancedConfig[me.profile] === "object" && typeof AdvancedConfig[me.profile].JoinDelay === "number") { + timeoutDelay("Custom Join Delay", AdvancedConfig[me.profile].JoinDelay * 1e3); + } else if (StarterConfig.JoinDelay) { + timeoutDelay("Join Game Delay", StarterConfig.JoinDelay * 1e3); + } } - joinGame(gameName, gamePass); + me.blockmouse = true; + + ControlAction.click(6, 594, 433, 172, 32); + me.blockmouse = false; lastGameStatus = "pending"; locationTimeout(5000, location); @@ -222,6 +498,17 @@ MainLoop: 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 { @@ -248,18 +535,47 @@ MainLoop: case getLocaleString(5207): D2Bot.updateStatus("Invalid Password"); D2Bot.printToConsole("Invalid Password"); + break; case getLocaleString(5208): 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 (StarterConfig.SwitchKeys) { - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + 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(); @@ -270,10 +586,19 @@ MainLoop: 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); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + break; } } @@ -309,9 +634,11 @@ MainLoop: break; } + updateCount(); timeoutDelay("Realm Down", StarterConfig.RealmDownDelay * 6e4); + D2Bot.CDKeyRD(); - if (StarterConfig.SwitchKeys) { + if (gameInfo.switchKeys) { D2Bot.printToConsole("Realm Down - Changing CD-Key"); timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); @@ -323,8 +650,6 @@ MainLoop: delay(500); ControlAction.click(6, 351, 337, 96, 32); break; - case 15: // New Character - break; case 16: // Character Select - Please Wait popup if (!locationTimeout(StarterConfig.PleaseWaitTimeout * 1e3, location)) { ControlAction.click(6, 351, 337, 96, 32); @@ -336,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 (StarterConfig.SwitchKeys) { - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + if (gameInfo.switchKeys) { + 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; @@ -357,18 +682,81 @@ MainLoop: break; case 22: // Login - Invalid Cdkey (classic or xpac) - if (StarterConfig.SwitchKeys) { - D2Bot.printToConsole("Invalid CD-Key"); - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); - D2Bot.restart(true); - } else { - timeoutDelay("Invalid CD-Key", StarterConfig.CDKeyInUseDelay * 6e4); + 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 + 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(); + } } break; @@ -383,29 +771,24 @@ MainLoop: 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 - D2Bot.printToConsole("Game doesn't exist"); - - lastGameStatus = "ready"; + //D2Bot.printToConsole("Game doesn't exist"); + ControlAction.click(6, 652, 469, 120, 20); + ControlAction.click(6, 433, 433, 96, 32); + timeoutDelay("Game doesn't exist", StarterConfig.GameDoesNotExistTimeout * 1e3); - if (!locationTimeout(StarterConfig.GameDoesNotExistTimeout * 1e3, location)) { - ControlAction.click(6, 652, 469, 120, 20); - ControlAction.click(6, 433, 433, 96, 32); - } + lastGameStatus = "DNE"; break; case 38: // Game is full - D2Bot.printToConsole("Game is full"); - - lastGameStatus = "ready"; - - delay(500); + badGames.push(joinInfo.gameName); ControlAction.click(6, 652, 469, 120, 20); - break; - case 42: // Empty character screen - delay(1000); - ControlAction.click(6, 33, 572, 128, 35); + ControlAction.click(6, 433, 433, 96, 32); + + lastGameStatus = "FULL"; break; default: diff --git a/d2bs/kolbot/D2BotFollow.dbj b/d2bs/kolbot/D2BotFollow.dbj index 35e9f825a..b5ae0015b 100644 --- a/d2bs/kolbot/D2BotFollow.dbj +++ b/d2bs/kolbot/D2BotFollow.dbj @@ -3,14 +3,15 @@ var StarterConfig = { FirstJoinMessage: "", // Message to say when first joining a channel, usually ".login" ChatActionsDelay: 2, // Seconds to wait in lobby before entering a channel - SwitchKeys: true, // Set to true to switch keys when they're in use, banned or after realm down - SwitchKeyDelay: 0, // Seconds to wait before switching a used/banned key or after realm down + JoinRetryDelay: 5, // Time in seconds to wait before next join attempt + SwitchKeyDelay: 5, // Seconds to wait before switching a used/banned key or after realm down - RealmDownDelay: 10, // Minutes to wait after getting Realm Down message + 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. SwitchKeys overrides this! ConnectingTimeout: 20, // Seconds to wait before cancelling the 'Connecting...' screen - PleaseWaitTimeout: 10, // Seconds to wait before cancelling the 'Please Wait...' screen + PleaseWaitTimeout: 30, // 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 }; @@ -28,7 +29,23 @@ var StarterConfig = { */ var JoinSettings = { - "leader": ["follower"] + "Leader": ["Leecher"] +}; + +// Advanced config - you don't have to edit this unless you need some of the features provided +var AdvancedConfig = { + /* Features: Override join delay for each profile + + * Format *: + "Profile Name": {JoinDelay: number_of_seconds} + + * Example * (don't edit this - it's just an example): + "MyProfile1": {JoinDelay: 3}, + "MyProfile2": {JoinDelay: 6} + */ + + // Put your lines under this one. Multiple entries are separated by commas. No comma after the last one. + }; @@ -36,72 +53,192 @@ var JoinSettings = { // No touchy! include("json2.js"); include("OOG.js"); - -var i, j, ingame, gameStart, difficulty, - leader = "", - lastGameStatus = "ready", - chatActionsDone = false, - connectFail = false, - D2BOT_JOIN = 1, - D2BOT_GAMEINFO = 2, - D2BOT_REQUESTGAME = 3, +include("automule.js"); +include("gambling.js"); +include("craftingsystem.js"); +include("torchsystem.js"); +include("common/misc.js"); + +var i, j, gameInfo, joinInfo, gameStart, ingame, handle, + firstLogin, chatActionsDone, lastGameTick, connectFail, gameCount = DataFile.getStats().runs + 1, - gamePass = "", gameName = "", nextGame = "", - isUp = "no"; + lastGameStatus = "ready", + leader = "", + lastGame = []; if (!FileTools.exists("data/" + me.profile + ".json")) { DataFile.create(); } -function timeoutDelay(text, time) { - var endTime = getTickCount() + time; +function locationTimeout(time, location) { + var endtime = getTickCount() + time; - while (getTickCount() < endTime) { - D2Bot.updateStatus(text + " (" + Math.floor((endTime - getTickCount()) / 1000) + "s)"); + while (!me.ingame && getLocation() === location && endtime > getTickCount()) { delay(500); } + + return (getLocation() !== location); } -function locationTimeout(time, location) { - var endtime = getTickCount() + time; +function updateCount() { + D2Bot.updateCount(); + delay(1000); + ControlAction.click(6, 264, 366, 272, 35); + + try { + login(me.profile); + } catch (e) { - while (getLocation() === location && endtime > getTickCount()) { - delay(500); } - return (getLocation() !== location); + delay(1000); + ControlAction.click(6, 33, 572, 128, 35); } -function RecieveCopyData(msgID, msg) { - switch (msgID) { - case D2BOT_GAMEINFO: +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; + } +} + +function ReceiveCopyData(mode, msg) { + var obj; + + switch (msg) { + case "Handle": + handle = mode; + + break; + } + + switch (mode) { + case 1: // JoinInfo + //print("Got Join Info"); + + joinInfo = JSON.parse(msg); + + break; + case 2: // Game info print("Recieved Game Info"); - [gameName, gamePass, difficulty] = msg.split('/'); + + gameInfo = JSON.parse(msg); + break; - case D2BOT_JOIN: - [nextGame, gamePass, isUp] = msg.split('/'); + 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); + + D2Bot.joinMe(obj.profile, me.gamename || "", "", me.gamepassword || "", me.gameReady ? "yes" : "no"); + } + break; - case D2BOT_REQUESTGAME: - D2Bot.joinMe(msg); + case 4: + // Heartbeat ping + if (msg === "pingreq") { + sendCopyData(null, me.windowtitle, 4, "pingrep"); + } + 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 main() { - addEventListener('copydata', RecieveCopyData); - delay(rand(1, 2) * 1000); + debugLog(me.profile); + addEventListener('copydata', ReceiveCopyData); + addEventListener('scriptmsg', ScriptMsgEvent); + + while (!handle) { + delay(100); + } + + DataFile.updateStats("handle", handle); + D2Bot.init(); + load("tools/heartbeat.js"); + + while (!gameInfo) { + D2Bot.requestGameInfo(); + delay(500); + } + + 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) { - if (me.gamepassword.toLowerCase() !== gamePass.toLowerCase()) { - print("leaving game"); - quit(); - } - - print("Updating Status"); - D2Bot.updateStatus("Game: " + me.gamename); + print("ÿc4Updating Status"); + //D2Bot.updateStatus("Game: " + me.gamename); lastGameStatus = "ingame"; ingame = true; @@ -109,18 +246,41 @@ function main() { DataFile.updateStats("runs", gameCount); } + + D2Bot.updateStatus("Game: " + me.gamename + timer(gameStart)); } delay(1000); } - locationAction(getLocation()); + locationAction(); delay(1000); } } -function locationAction(location) { - var i, string, text; +function joinCheck(leader) { + D2Bot.requestGame(leader); + delay(500); + + //print(leader + " " + joinInfo.inGame + " " + lastGame.toSource() + " " + joinInfo.gameName); + + if (!joinInfo.inGame || (lastGame.length && lastGame.indexOf(joinInfo.gameName) === -1)) { + D2Bot.printToConsole("Game is finished. Stopping join delay."); + + return true; + } + + return false; +} + +function locationAction() { + if (me.ingame) { + return; + } + + var i, string, text, location; + + location = getLocation(); MainSwitch: switch (location) { @@ -129,6 +289,10 @@ MainSwitch: case 1: // Lobby D2Bot.updateStatus("Lobby"); + if (!firstLogin) { + firstLogin = true; + } + if (StarterConfig.JoinChannel !== "") { ControlAction.click(6, 27, 480, 120, 20); @@ -136,9 +300,14 @@ MainSwitch: } if (ingame) { + if (AutoMule.outOfGameCheck() || TorchSystem.outOfGameCheck() || Gambling.outOfGameCheck() || CraftingSystem.outOfGameCheck()) { + break; + } + print("updating runs"); D2Bot.updateRuns(); + lastGameTick = getTickCount(); gameCount += 1; lastGameStatus = "ready"; ingame = false; @@ -162,15 +331,21 @@ MainSwitch: 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 (ingame) { + if (AutoMule.outOfGameCheck() || TorchSystem.outOfGameCheck() || Gambling.outOfGameCheck() || CraftingSystem.outOfGameCheck()) { + break; + } + print("updating runs"); D2Bot.updateRuns(); + lastGameTick = getTickCount(); gameCount += 1; lastGameStatus = "ready"; ingame = false; @@ -179,7 +354,7 @@ MainSwitch: if (!chatActionsDone) { chatActionsDone = true; - timeoutDelay("Chat delay", StarterConfig.ChatActionsDelay * 1e3); + ControlAction.timeoutDelay("Chat delay", StarterConfig.ChatActionsDelay * 1e3); say("/j " + StarterConfig.JoinChannel); delay(1000); @@ -210,49 +385,84 @@ MainSwitch: D2Bot.updateStatus("Join Game"); if (!leader) { -JoinLoop: + leader = []; + for (i in JoinSettings) { if (JoinSettings.hasOwnProperty(i) && typeof i === "string") { for (j = 0; j < JoinSettings[i].length; j += 1) { if (JoinSettings[i][j] === me.profile || JoinSettings[i][j] === "all") { - leader = i; - - break JoinLoop; + leader.push(i); } } } } } - if (!leader) { + if (!leader || !leader.length) { break; } +JoinLoop2: for (i = 0; i < 5; i += 1) { - D2Bot.requestGame(leader); + for (j = 0; j < leader.length; j += 1) { + joinInfo = false; - if (nextGame !== "") { - break; - } + D2Bot.requestGame(leader[j]); + delay(100); - delay(100); - } + if (joinInfo && joinInfo.gameName !== "" && (lastGame.indexOf(joinInfo.gameName) === -1 || lastGameStatus === "pending")) { + ControlAction.setText(1, 606, 148, 155, 20, joinInfo.gamePass); + ControlAction.setText(1, 432, 148, 155, 20, joinInfo.gameName); - if (nextGame !== "" && (nextGame !== gameName || lastGameStatus === "pending")) { - ControlAction.setText(1, 606, 148, 155, 20, gamePass); - ControlAction.setText(1, 432, 148, 155, 20, nextGame); + 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]); + delay(200); - if (isUp !== "yes") { - break; - } + if (!joinInfo.inGame) { + lastGameStatus = "ready"; + + break; + } + } + + if (!joinInfo.inGame) { + continue; + } + + // Don't join immediately after previous game to avoid FTJ + if (getTickCount() - lastGameTick < 5000) { + ControlAction.timeoutDelay("Game Delay", (lastGameTick - getTickCount() + 5000)); + } + + print("joining game " + joinInfo.gameName); + + if (typeof AdvancedConfig[me.profile] === "object" && typeof AdvancedConfig[me.profile].JoinDelay === "number") { + ControlAction.timeoutDelay("Custom Join Delay", AdvancedConfig[me.profile].JoinDelay * 1e3); + } + + me.blockMouse = true; - print("joining game " + nextGame); - ControlAction.click(6, 594, 433, 172, 32); + DataFile.updateStats("gameName", joinInfo.gameName); + ControlAction.click(6, 594, 433, 172, 32); - gameName = nextGame; - lastGameStatus = "pending"; + me.blockMouse = false; - locationTimeout(5000, location); + lastGame.push(joinInfo.gameName); + + if (lastGame.length > leader.length) { // Might need a fixed number. Right now it stores 1 game per leader. + lastGame.shift(); + } + + lastGameStatus = "pending"; + + locationTimeout(15000, location); + + break JoinLoop2; + } + } } break; @@ -264,12 +474,23 @@ JoinLoop: 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); + print(e + " " + getLocation()); } break; @@ -290,18 +511,47 @@ JoinLoop: case getLocaleString(5207): D2Bot.updateStatus("Invalid Password"); D2Bot.printToConsole("Invalid Password"); + break; case getLocaleString(5208): 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 (StarterConfig.SwitchKeys) { - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); } else { D2Bot.stop(); @@ -312,10 +562,19 @@ JoinLoop: 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); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + break; } } @@ -331,17 +590,17 @@ JoinLoop: D2Bot.updateStatus("Unable To Connect"); if (connectFail) { - timeoutDelay("Unable to Connect", StarterConfig.UnableToConnectDelay * 6e4); + 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"); @@ -351,12 +610,17 @@ JoinLoop: break; } - timeoutDelay("Realm Down", StarterConfig.RealmDownDelay * 6e4); + updateCount(); + ControlAction.timeoutDelay("Realm Down", StarterConfig.RealmDownDelay * 6e4); + D2Bot.CDKeyRD(); - if (StarterConfig.SwitchKeys) { + if (gameInfo.switchKeys && !gameInfo.rdBlocker) { D2Bot.printToConsole("Realm Down - Changing CD-Key"); - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); + } else { + D2Bot.printToConsole("Realm Down - Restart"); + D2Bot.restart(); } break; @@ -364,8 +628,7 @@ JoinLoop: D2Bot.updateStatus("Disconnected"); delay(500); ControlAction.click(6, 351, 337, 96, 32); - break; - case 15: // New Character + break; case 16: // Character Select - Please Wait popup if (!locationTimeout(StarterConfig.PleaseWaitTimeout * 1e3, location)) { @@ -376,16 +639,17 @@ JoinLoop: 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("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 (StarterConfig.SwitchKeys) { - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); } else { - timeoutDelay("CD-Key in use", StarterConfig.CDKeyInUseDelay * 6e4); + ControlAction.timeoutDelay("CD-Key in use", StarterConfig.CDKeyInUseDelay * 6e4); ControlAction.click(6, 335, 450, 128, 35); } @@ -399,18 +663,81 @@ JoinLoop: break; case 22: // Login - Invalid Cdkey (classic or xpac) - if (StarterConfig.SwitchKeys) { - D2Bot.printToConsole("Invalid CD-Key"); - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); - D2Bot.restart(true); - } else { - timeoutDelay("Invalid CD-Key", StarterConfig.CDKeyInUseDelay * 6e4); + 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 + 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(); + } } break; @@ -425,34 +752,38 @@ JoinLoop: 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 D2Bot.printToConsole("Game doesn't exist"); - lastGameStatus = "ready"; + if (gameInfo.rdBlocker) { + D2Bot.printToConsole(gameInfo.mpq + " is probably flagged.", 6); - if (!locationTimeout(StarterConfig.GameDoesNotExistTimeout * 1e3, location)) { - ControlAction.click(6, 652, 469, 120, 20); - ControlAction.click(6, 433, 433, 96, 32); + 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 D2Bot.printToConsole("Game is full"); + ControlAction.click(6, 652, 469, 120, 20); + lastGame.push(joinInfo.gameName); lastGameStatus = "ready"; - delay(500); - ControlAction.click(6, 652, 469, 120, 20); - break; - case 42: // Empty character screen - delay(1000); - ControlAction.click(6, 33, 572, 128, 35); - break; default: if (location !== undefined) { D2Bot.printToConsole("Unhandled location " + location); + //takeScreenshot(); delay(500); D2Bot.restart(); } diff --git a/d2bs/kolbot/D2BotLead.dbj b/d2bs/kolbot/D2BotLead.dbj index 7c1d5f8e5..d032b4a11 100644 --- a/d2bs/kolbot/D2BotLead.dbj +++ b/d2bs/kolbot/D2BotLead.dbj @@ -1,72 +1,159 @@ var StarterConfig = { - MinGameTime: 180, // Minimum game length in seconds. If a game is ended too soon, the rest of the time is waited in the lobby - CreateGameDelay: 5, // Seconds to wait before creating a new game - - JoinChannel: "", // Name of the channel to join - FirstJoinMessage: "", // Message to say when first joining a channel, usually ".login" - AnnounceGames: false, // Announce next game in channel + MinGameTime: 120, // 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: 10, // Seconds to wait before creating a new game + ResetCount: 999, // 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 - SwitchKeys: true, // Set to true to switch keys when they're in use, banned or after realm down - SwitchKeyDelay: 0, // Seconds to wait before switching a used/banned key or after realm down + // ChannelConfig can override these options for individual profiles. + 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 - RealmDownDelay: 10, // Minutes to wait after getting Realm Down message + 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: 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. SwitchKeys overrides this! + 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 }; +var ChannelConfig = { + /* Override default values for JoinChannel, FirstJoinMessage, AnnounceGames and AfterGameMessage per profile + It's possible to override any number of these options (you don't have to put all of them) + + **** DO NOT EDIT ANYTHING INSIDE THIS COMMENT BLOCK *** + + Format: + + "Profile Name": { + JoinChannel: "channel name", -OR- ["channel 1", "channel 2"], + FirstJoinMessage: "first message", -OR- ["join msg 1", "join msg 2"], + AnnounceGames: true, + AfterGameMessage: "message after a finished run" -OR- ["msg 1", msg 2"] + } + + Multiple entries are separated by a comma + + Examples: + + "Profile 1": { + JoinChannel: "my channel", + FirstJoinMessage: ".login", + AnnounceGames: true, + AfterGameMessage: "follow my runs or die" + }, + "Profile 2": { + JoinChannel: ["channel 1", "channel 2"], + FirstJoinMessage: [".login", "^login"], + AfterGameMessage: ["follow my runs or die", "seriously, you'll die"] + } + */ + + // Add your lines here + +}; + // No touchy! include("json2.js"); include("OOG.js"); +include("automule.js"); include("gambling.js"); +include("craftingsystem.js"); +include("torchsystem.js"); +include("common/misc.js"); -var D2BOT_JOIN = 1, - D2BOT_GAMEINFO = 2, - D2BOT_REQUESTGAME = 3, - lastGameStatus = "ready", - chatActionsDone = false, - connectFail = false, +if (!FileTools.exists("data/" + me.profile + ".json")) { + DataFile.create(); +} + +var gameInfo, gameStart, ingame, chatActionsDone, pingQuit, + handle, useChat, firstLogin, connectFail, gameCount = DataFile.getStats().runs + 1, - gamePass = "", - gameName = "", - difficulty, - gameStart, + lastGameStatus = "ready", isUp = "no", - nextGame = "", - ingame = false; + chanInfo = { + joinChannel: "", + firstMsg: "", + afterMsg: "", + announce: false + }; + +function sayMsg(string) { + if (!useChat) { + return; + } -if (!FileTools.exists("data/" + me.profile + ".json")) { - DataFile.create(); + say(string); } -function RecieveCopyData(msgID, msg) { - switch (msgID) { - case D2BOT_GAMEINFO: +function ReceiveCopyData(mode, msg) { + var obj; + + switch (msg) { + case "Handle": + handle = mode; + + break; + } + + switch (mode) { + case 2: // Game info print("Recieved Game Info"); - [gameName, gamePass, difficulty] = msg.split('/'); + + 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 D2BOT_JOIN: - [nextGame, gamePass, isUp] = msg.split('/'); + case 4: // Heartbeat ping + if (msg === "pingreq") { + sendCopyData(null, me.windowtitle, 4, "pingrep"); + } + break; - case D2BOT_REQUESTGAME: - D2Bot.joinMe(msg, gameName, gameCount, gamePass, isUp); + case 0xf124: // Cached info retreival + if (msg !== "null") { + gameInfo.crashInfo = JSON.parse(msg); + } + break; } } -function timeoutDelay(text, time) { - var endTime = getTickCount() + time; +function setNextGame() { + var nextGame = gameInfo.gameName; - while (getTickCount() < endTime) { - D2Bot.updateStatus(text + " (" + Math.floor((endTime - getTickCount()) / 1000) + "s)"); - delay(500); + if (StarterConfig.ResetCount && gameCount + 1 >= StarterConfig.ResetCount) { + nextGame += 1; + } else { + nextGame += (gameCount + 1); } + + DataFile.updateStats("nextGame", nextGame); } function locationTimeout(time, location) { @@ -94,10 +181,118 @@ function updateCount() { ControlAction.click(6, 33, 572, 128, 35); } +function ScriptMsgEvent(msg) { + switch (msg) { + case "mule": + AutoMule.check = true; + + break; + case "muleTorch": + 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.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() { - addEventListener('copydata', RecieveCopyData); - delay(rand(1, 2) * 1000); - D2Bot.requestGameInfo(); + 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 (!!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 @@ -105,20 +300,19 @@ function main() { isUp = "yes"; if (!ingame) { - if (me.gamepassword.toLowerCase() !== gamePass.toLowerCase()) { - print("leaving game"); - quit(); - } + gameStart = getTickCount(); print("Updating Status"); - D2Bot.updateStatus("Game: " + me.gamename); + //D2Bot.updateStatus("Game: " + me.gamename); lastGameStatus = "ingame"; ingame = true; - gameStart = getTickCount(); DataFile.updateStats("runs", gameCount); + DataFile.updateStats("ingameTick"); } + + D2Bot.updateStatus("Game: " + me.gamename + timer(gameStart)); } delay(1000); @@ -132,7 +326,7 @@ function main() { } function locationAction(location) { - var i, string, text, gambleGame; + var i, control, string, text; MainSwitch: switch (location) { @@ -141,13 +335,43 @@ MainSwitch: case 1: // Lobby D2Bot.updateStatus("Lobby"); - if (StarterConfig.JoinChannel !== "") { + if (!firstLogin) { + firstLogin = true; + } + + if (lastGameStatus === "pending") { + gameCount += 1; + } + + if (StarterConfig.PingQuitDelay && pingQuit) { + ControlAction.timeoutDelay("Ping Delay", StarterConfig.PingQuitDelay * 1e3); + + pingQuit = false; + } + + if (StarterConfig.JoinChannel !== "" || (ChannelConfig[me.profile] && ChannelConfig[me.profile].JoinChannel !== "")) { ControlAction.click(6, 27, 480, 120, 20); break; } + 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(); @@ -155,23 +379,12 @@ MainSwitch: lastGameStatus = "ready"; ingame = false; - if (getTickCount() - gameStart < StarterConfig.MinGameTime * 1e3) { - timeoutDelay("Min game time wait", StarterConfig.MinGameTime * 1e3 + gameStart - getTickCount()); - } - } - - // #### experimental gambling system start #### - gambleGame = Gambling.checkGamblers(); + if (StarterConfig.ResetCount && gameCount >= StarterConfig.ResetCount) { + gameCount = 1; - if (gambleGame && DataFile.getStats().gold > Gambling.minGold) { - delay(3000); - joinGame(gambleGame[0], gambleGame[1]); - delay(1000); - locationTimeout(5000, location); - - break; + DataFile.updateStats("runs", gameCount); + } } - // #### experimental gambling system end #### if (!ControlAction.click(6, 533, 469, 120, 20)) { // Create break; @@ -191,12 +404,33 @@ MainSwitch: 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 === "pending") { + gameCount += 1; + } + + 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(); @@ -204,40 +438,82 @@ MainSwitch: lastGameStatus = "ready"; ingame = false; - if (getTickCount() - gameStart < StarterConfig.MinGameTime * 1e3) { - timeoutDelay("Min game time wait", StarterConfig.MinGameTime * 1e3 + gameStart - getTickCount()); + if (StarterConfig.ResetCount && gameCount >= StarterConfig.ResetCount) { + gameCount = 1; + + DataFile.updateStats("runs", gameCount); } - } - // #### experimental gambling system start #### - gambleGame = Gambling.checkGamblers(); + if (ChannelConfig[me.profile] && ChannelConfig[me.profile].hasOwnProperty("AfterGameMessage")) { + chanInfo.afterMsg = ChannelConfig[me.profile].AfterGameMessage; + } else { + chanInfo.afterMsg = StarterConfig.AfterGameMessage; + } - if (gambleGame && DataFile.getStats().gold > Gambling.minGold) { - delay(3000); - joinGame(gambleGame[0], gambleGame[1]); - delay(1000); - locationTimeout(5000, location); + if (chanInfo.afterMsg) { + if (typeof chanInfo.afterMsg === "string") { + chanInfo.afterMsg = [chanInfo.afterMsg]; + } - break; + for (i = 0; i < chanInfo.afterMsg.length; i += 1) { + sayMsg(chanInfo.afterMsg[i]); + delay(500); + } + } } - // #### experimental gambling system end #### if (!chatActionsDone) { chatActionsDone = true; - timeoutDelay("Chat delay", StarterConfig.ChatActionsDelay * 1e3); - say("/j " + StarterConfig.JoinChannel); - delay(1000); + if (ChannelConfig[me.profile] && ChannelConfig[me.profile].hasOwnProperty("JoinChannel")) { + chanInfo.joinChannel = ChannelConfig[me.profile].JoinChannel; + } else { + chanInfo.joinChannel = StarterConfig.JoinChannel; + } - if (StarterConfig.FirstJoinMessage !== "") { - say(StarterConfig.FirstJoinMessage); - delay(500); + if (ChannelConfig[me.profile] && ChannelConfig[me.profile].hasOwnProperty("FirstJoinMessage")) { + chanInfo.firstMsg = ChannelConfig[me.profile].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); + } + } } } - if (StarterConfig.AnnounceGames) { - delay(1000); - say("Next game is " + gameName + gameCount + (gamePass === "" ? "" : "//" + gamePass)); + // Announce game + if (ChannelConfig[me.profile] && ChannelConfig[me.profile].hasOwnProperty("AnnounceGames")) { + chanInfo.announce = ChannelConfig[me.profile].AnnounceGames; + } else { + chanInfo.announce = StarterConfig.AnnounceGames; + } + + if (chanInfo.announce) { + sayMsg("Next game is " + gameInfo.gameName + gameCount + (gameInfo.gamePass === "" ? "" : "//" + gameInfo.gamePass)); } if (!ControlAction.click(6, 533, 469, 120, 20)) { // Create @@ -258,21 +534,41 @@ MainSwitch: case 4: // Create Game D2Bot.updateStatus("Creating Game"); - while (!gameName) { + control = getControl(1, 657, 342, 27, 20); + + // Set character difference + if (typeof StarterConfig.CharacterDifference === "number") { + if (control.disabled === 4) { + ControlAction.click(6, 431, 341, 15, 16); + } + + ControlAction.setText(1, 657, 342, 27, 20, StarterConfig.CharacterDifference.toString()); + } else if (StarterConfig.CharacterDifference === false && control.disabled === 5) { + ControlAction.click(6, 431, 341, 15, 16); + } + + // Get game name if there is none + while (!gameInfo.gameName) { D2Bot.requestGameInfo(); delay(500); } + // FTJ handler if (lastGameStatus === "pending") { - gameCount += 1; + isUp = "no"; + + D2Bot.printToConsole("Failed to create game"); + ControlAction.timeoutDelay("FTJ delay", StarterConfig.FTJDelay * 1e3); + D2Bot.updateRuns(); } - timeoutDelay("Make Game Delay", StarterConfig.CreateGameDelay * 1e3); - createGame(gameName + gameCount, gamePass, difficulty === "Hell" ? 2 : difficulty === "Nightmare" ? 1 : 0); + ControlAction.createGame(gameInfo.gameName + gameCount, gameInfo.gamePass, gameInfo.difficulty, StarterConfig.CreateGameDelay * 1000); lastGameStatus = "pending"; - locationTimeout(5000, location); + setNextGame(); + locationTimeout(10000, location); + break; case 5: // Join Game break; @@ -282,13 +578,25 @@ MainSwitch: 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); + print(e + " " + getLocation()); } break; @@ -309,18 +617,47 @@ MainSwitch: case getLocaleString(5207): D2Bot.updateStatus("Invalid Password"); D2Bot.printToConsole("Invalid Password"); + break; case getLocaleString(5208): 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 (StarterConfig.SwitchKeys) { - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + 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(); @@ -331,10 +668,19 @@ MainSwitch: 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); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + break; } } @@ -350,7 +696,7 @@ MainSwitch: D2Bot.updateStatus("Unable To Connect"); if (connectFail) { - timeoutDelay("Unable to Connect", StarterConfig.UnableToConnectDelay * 6e4); + ControlAction.timeoutDelay("Unable to Connect", StarterConfig.UnableToConnectDelay * 6e4); connectFail = false; } @@ -361,14 +707,6 @@ MainSwitch: connectFail = true; - break; - case 12: // Character Select - try { - login(me.profile); - } catch (e2) { - - } - break; case 13: // Realm Down - Character Select screen D2Bot.updateStatus("Realm Down"); @@ -379,13 +717,15 @@ MainSwitch: } updateCount(); - timeoutDelay("Realm Down", StarterConfig.RealmDownDelay * 6e4); + ControlAction.timeoutDelay("Realm Down", StarterConfig.RealmDownDelay * 6e4); + D2Bot.CDKeyRD(); - if (StarterConfig.SwitchKeys) { + if (gameInfo.switchKeys && !gameInfo.rdBlocker) { D2Bot.printToConsole("Realm Down - Changing CD-Key"); - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); D2Bot.restart(true); } else { + D2Bot.printToConsole("Realm Down - Restart"); D2Bot.restart(); } @@ -394,8 +734,7 @@ MainSwitch: D2Bot.updateStatus("Disconnected"); delay(500); ControlAction.click(6, 351, 337, 96, 32); - break; - case 15: // New Character + break; case 16: // Character Select - Please Wait popup if (!locationTimeout(StarterConfig.PleaseWaitTimeout * 1e3, location)) { @@ -406,17 +745,18 @@ MainSwitch: 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("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 (StarterConfig.SwitchKeys) { - timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + if (gameInfo.switchKeys) { + 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; @@ -429,19 +769,81 @@ MainSwitch: break; case 22: // Login - Invalid Cdkey (classic or xpac) - if (StarterConfig.SwitchKeys) { - D2Bot.printToConsole("Invalid CD-Key"); - 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); + 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 + 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(); + } } break; @@ -454,37 +856,40 @@ MainSwitch: break; case 26: // Lobby - Game Name Exists + ControlAction.click(6, 533, 469, 120, 20); + gameCount += 1; + lastGameStatus = "ready"; - delay(500); - ControlAction.click(6, 533, 469, 120, 20); 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"); - lastGameStatus = "ready"; - - locationTimeout(StarterConfig.GameDoesNotExistTimeout * 1e3, location); + if (gameInfo.rdBlocker) { + D2Bot.printToConsole(gameInfo.mpq + " is probably flagged.", 6); - break; - case 38: // Game is full - D2Bot.printToConsole("Game is full"); + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } + } else { + locationTimeout(StarterConfig.GameDoesNotExistTimeout * 1e3, location); + } lastGameStatus = "ready"; - delay(500); - ControlAction.click(6, 652, 469, 120, 20); break; - case 42: // Empty character screen - delay(1000); - ControlAction.click(6, 33, 572, 128, 35); - + 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(); } diff --git a/d2bs/kolbot/D2BotMap.dbj b/d2bs/kolbot/D2BotMap.dbj new file mode 100644 index 000000000..3be2b66dd --- /dev/null +++ b/d2bs/kolbot/D2BotMap.dbj @@ -0,0 +1,58 @@ +function main() { + include("json2.js"); + include("OOG.js"); + include("common/misc.js"); + + var handle, + isUp = "no"; + + function copyDataEvent(mode, msg) { + switch (msg) { + case "Handle": + handle = mode; + + break; + } + + switch (mode) { + case 3: // request game + var obj = JSON.parse(msg); + + if (me.gameReady) { + D2Bot.joinMe(obj.profile, me.gamename.toLowerCase(), "", me.gamepassword.toLowerCase(), isUp); + } + + break; + case 4: + // Heartbeat ping + if (msg === "pingreq") { + sendCopyData(null, me.windowtitle, 4, "pingrep"); + } + + break; + } + } + + addEventListener('copydata', copyDataEvent); + + while (!handle) { + delay(100); + } + + DataFile.updateStats("handle", handle); + delay(500); + D2Bot.init(); + load("tools/heartbeat.js"); + + while (true) { + if (me.gameReady) { + if (isUp === "no") { + isUp = "yes"; + } + } else { + isUp = "no"; + } + + delay(1000); + } +} \ No newline at end of file diff --git a/d2bs/kolbot/D2BotMule.dbj b/d2bs/kolbot/D2BotMule.dbj new file mode 100644 index 000000000..ae7276961 --- /dev/null +++ b/d2bs/kolbot/D2BotMule.dbj @@ -0,0 +1,1007 @@ +var StarterConfig = { + SwitchKeyDelay: 0, // Seconds to wait before switching a used/banned key or after realm down + 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 master, gameInfo, connectFail, makeAcc, joinInfo, + muleMode, muleFilename, muleObj, handle, + makeNext = false, + status = "loading", + masterStatus = { + status: "" + }; + +// Mule Data object manipulates external mule datafile +var MuleData = { + // create a new mule datafile + create: function () { + var obj, string; + + obj = { + account: "", + accNum: 0, + character: "", + charNum: 0, + fullChars: [], + torchChars: [] + }; + + string = JSON.stringify(obj); + + FileTools.writeText(muleFilename, string); + }, + + // read data from the mule datafile and return the data object + read: function () { + var obj, string; + + string = FileTools.readText(muleFilename); + obj = JSON.parse(string); + + return obj; + }, + + // write a data object to the mule datafile + write: function (obj) { + var string; + + string = JSON.stringify(obj); + + FileTools.writeText(muleFilename, string); + } +}; + +// stash picked items +function stashItems() { + var i, + items = me.getItems(); + + for (i = 0; i < items.length; i += 1) { + if (items[i].mode === 0 && items[i].location === 3) { + Storage.Stash.MoveTo(items[i]); + } + } + + return true; +} + +// pick items from ground +function pickItems() { + var i, items, canFit, item, + rval = "fail", + list = []; + + while (!me.name || !me.gameReady) { + if (!me.ingame) { + return rval; + } + + delay(100); + } + + //delay(1000); + + for (i = 0; i < 100; i += 1) { + items = me.findItems(-1, 0, 3); + + if (items) { + break; + } + + 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 === 0 || items[i].classid !== 530)) { // don't drop ID scroll with torch/anni mules + try { + items[i].drop(); + } catch (dropError) { + print("Failed to drop an item."); + } + } + } + } + + while (me.gameReady) { + if (masterStatus.status === "done") { + item = getUnit(4); + + if (item) { + do { + 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()); + } + + // If and only if there is nothing left are we "done" + if (list.length === 0) { + rval = "done"; + + break; + } + + while (list.length > 0) { + item = list.shift(); + canFit = Storage.Inventory.CanFit(item); + + // Torch handling + 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(); + + canFit = Storage.Inventory.CanFit(item); + } + + if (canFit) { + Pickit.pickItem(item); + } else { + rval = "next"; + } + } + + if (rval === "next") { + break; + } + } else { + sendCopyData(null, master, 10, JSON.stringify({status: "report"})); + //D2Bot.shoutGlobal("report", 0); + } + + delay(500); + } + + return rval; +} + +// master/mule communication function +function ReceiveCopyData(mode, msg) { + var obj, masterInfo; + + switch (msg) { + case "Handle": + handle = mode; + + break; + } + + // mode check instead of msg check because of crashes + switch (mode) { + case 1: // JoinInfo + //print("Got Join Info"); + + joinInfo = JSON.parse(msg); + + break; + case 2: // game info + print("Recieved Game Info"); + + gameInfo = JSON.parse(msg); + + break; + case 3: // request game + break; + case 4: + // Heartbeat ping + if (msg === "pingreq") { + sendCopyData(null, me.windowtitle, 4, "pingrep"); + } + + break; + // automule specific + case 10: // mule request + obj = JSON.parse(msg); + + if (!master) { + masterInfo = AutoMule.getMaster(obj); + + if (masterInfo) { + master = masterInfo.profile; + muleMode = masterInfo.mode; + } + } else { + if (obj.profile === master) { + sendCopyData(null, master, 10, JSON.stringify({status: status})); + } else { + sendCopyData(null, obj.profile, 10, JSON.stringify({status: "busy"})); + } + } + + break; + case 11: // begin item pickup + status = "begin"; + + break; + case 12: // get master's status + masterStatus = JSON.parse(msg); + + break; + } +} + +// set next account - increase account number in mule datafile +function nextAccount() { + var obj = MuleData.read(); + + obj.accNum = obj.accNum + 1; + obj.account = muleObj.accountPrefix + obj.accNum; + obj.character = ""; + obj.charNum = 0; + obj.fullChars = []; + obj.torchChars = []; + + MuleData.write(obj); + + return obj.account; +} + +// set next character - increase character number in mule datafile +function nextChar() { + var i, num, + charSuffix = "", + charNumbers = "abcdefghijklmnopqrstuvwxyz", + obj = MuleData.read(); + + /*if (getLocation() === 12) { + obj.charNum = ControlAction.getCharacters().length; + }*/ + + // dirty + if (obj.charNum > 25) { + obj.charNum = 0; + } + + num = obj.accNum.toString(); + + for (i = 0; i < num.length; i += 1) { + charSuffix += charNumbers[parseInt(num[i], 10)]; + } + + charSuffix += charNumbers[obj.charNum]; + obj.charNum = obj.charNum + 1; + obj.character = muleObj.charPrefix + charSuffix; + + MuleData.write(obj); + + return obj.character; +} + +function locationTimeout(time, location) { + var endtime = getTickCount() + time; + + while (getLocation() === location && endtime > getTickCount()) { + delay(500); + } + + 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; + + while (getTickCount() < endTime) { + D2Bot.updateStatus(text + " (" + Math.floor((endTime - getTickCount()) / 1000) + "s)"); + delay(500); + } +} + +function updateCount() { + D2Bot.updateCount(); + delay(1000); + ControlAction.click(6, 264, 366, 272, 35); + + var info, + obj = MuleData.read(); + + info = { + realm: muleObj.realm, + account: obj.account, + password: muleObj.accountPassword + }; + + ControlAction.loginAccount(info); + delay(1000); + ControlAction.click(6, 33, 572, 128, 35); +} + +function checkAnniTorch() { + while (!me.gameReady) { + delay(500); + } + + return me.findItem(603, 0, -1, 7) || me.findItem(604, 0, -1, 7); +} + +function foreverAlone() { + var party = getParty(); + + if (party) { + do { + if (party.name !== me.name) { + return false; + } + } while (party.getNext()); + } + + return true; +} + +include("json2.js"); +include("oog.js"); +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"); +include("common/pather.js"); +include("common/misc.js"); +include("common/config.js"); +include("common/prototypes.js"); +include("common/collmap.js"); + +addEventListener("copydata", ReceiveCopyData); + +function main() { + while (!handle) { + delay(100); + } + + DataFile.updateStats("handle", handle); + D2Bot.init(); + load("tools/heartbeat.js"); + + while (!gameInfo) { + D2Bot.requestGameInfo(); + 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(100); + } + + print("Master found: " + master); + + muleObj = AutoMule.getMuleObject(muleMode, master); + muleFilename = AutoMule.getMuleFilename(muleMode, master); + + print("Mule filename: " + muleFilename); + + var obj, tick, + inGame = false; + + try { + // ugly solution to uglier problem - pickItem area update + if (!FileTools.exists("data/" + me.profile + ".json")) { + DataFile.create(); + } + + // create mule datafile if it doesn't exist + if (!FileTools.exists(muleFilename)) { + MuleData.create(); + } + + obj = MuleData.read(); + + if (obj.account && obj.account.indexOf(muleObj.accountPrefix) < 0) { + MuleData.create(); + } + } catch (e) { + print("Caught exception creating data files."); + print(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 (!inGame) { + if (status !== "begin") { + status = "ready"; + } + + 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; + } + + 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(me.profile, true); + } + + me.overhead("begin"); + + switch (pickItems()) { + // done picking, tell the master to leave game and kill mule profile + case "done": + MuleLogger.logChar(); + + obj = MuleData.read(); + + 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(me.profile, true); + + return; + // can't fit more items, get to next character or account + case "next": + MuleLogger.logChar(); + //delay(500); + + makeNext = true; + obj = MuleData.read(); + + if (checkAnniTorch()) { + obj.torchChars.push(me.name); + } + + obj.fullChars.push(me.name); + MuleData.write(obj); + nextChar(); + 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 + break; + } + } + + if (!me.ingame) { + delay(1000); + locationAction(getLocation()); + } + } catch (e2) { + print("Caught an exception in the main loop."); + print(e2); + D2Bot.printToConsole("MainLoopException: " + e2.message + " (" + e2.fileName.substring(e2.fileName.lastIndexOf("\\") + 1, e2.fileName.length) + " #" + e2.lineNumber + ")"); + } + + delay(100); + } +} + +function locationAction(location) { + var i, obj, info, control, string, text; + +MainSwitch: + switch (location) { + case 1: + case 3: + D2Bot.updateStatus("Lobby"); + + if (makeNext) { + ControlAction.click(6, 693, 490, 80, 20); + + break; + } + + 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 + D2Bot.updateStatus("Creating Game"); + + control = getControl(1, 657, 342, 27, 20); + + if (control && control.disabled === 5) { + ControlAction.click(6, 431, 341, 15, 16); // remove level restriction + } + + delay(2000); + createGame(muleObj.muleGameName[0], muleObj.muleGameName[1]); + ingameTimeout(5000); + + break; + case 2: // Waiting In Line + D2Bot.updateStatus("Waiting..."); + locationTimeout(StarterConfig.WaitInLineTimeout * 1e3, location); + ControlAction.click(6, 433, 433, 96, 32); + + break; + case 5: // Join Game + D2Bot.updateStatus("Join Game"); + 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 + break; + case 7: // Channel List + break; + case 8: // menu + case 9: // login + if (makeNext) { + makeNext = false; + } + + obj = MuleData.read(); + + if (!obj.account || obj.account.indexOf(muleObj.accountPrefix) < 0) { + nextAccount(); + + obj = MuleData.read(); + } + + info = { + realm: muleObj.realm, + account: obj.account, + password: muleObj.accountPassword + }; + + if (makeAcc) { + ControlAction.makeAccount(info); + //FileTools.writeText("mules/" + info.account + ".txt", ""); + D2Bot.printToConsole("Made account: " + info.account, 7); + + makeAcc = false; + + break; + } + + ControlAction.loginAccount(info); + + 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): + 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: " + 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(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; + 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); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(me.profile, true); + } + + 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) { + 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(); + timeoutDelay("Realm Down", StarterConfig.RealmDownDelay * 6e4); + D2Bot.CDKeyRD(); + + if (gameInfo.switchKeys) { + D2Bot.printToConsole("Realm Down - Changing CD-Key"); + timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.restart(); + } + + break; + case 14: // Character Select / Main Menu - Disconnected + D2Bot.updateStatus("Disconnected"); + delay(500); + ControlAction.click(6, 351, 337, 96, 32); + + break; + case 18: // splash + ControlAction.click(); + + break; + case 12: // char select + 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); + + break; + } + + // Can't create character, button greyed out = high likelyhood of realm down + if (getLocation() === 42 && getControl(6, 33, 528, 168, 60).disabled === 4) { + D2Bot.updateStatus("Realm Down"); + delay(1000); + + if (!ControlAction.click(6, 33, 572, 128, 35)) { + break; + } + + updateCount(); + timeoutDelay("Realm Down", StarterConfig.RealmDownDelay * 6e4); + D2Bot.CDKeyRD(); + + if (gameInfo.switchKeys) { + D2Bot.printToConsole("Realm Down - Changing CD-Key"); + timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.restart(); + } + } + + obj = MuleData.read(); + + if (makeNext) { + if (obj.fullChars.length === 8 || (muleMode > 0 && obj.torchChars.length === 8)) { + ControlAction.click(6, 33, 572, 128, 35); + nextAccount(); + + break; + } + + makeNext = false; + } + + if (!obj.character || obj.character.indexOf(muleObj.charPrefix) < 0) { + nextChar(); + + obj = MuleData.read(); + } + + info = { + account: obj.account, + charName: obj.character, + ladder: muleObj.ladder, + hardcore: muleObj.hardcore, + expansion: muleObj.expansion, + charClass: "amazon" + }; + + if (muleMode > 0 && obj.torchChars.indexOf(info.charName) > -1) { + nextChar(); + + break; + } + + if (ControlAction.findCharacter(info)) { + ControlAction.loginCharacter(info); + } else { + if (ControlAction.getCharacters().length >= 8) { // premade account that's already full + ControlAction.click(6, 33, 572, 128, 35); + nextAccount(); + + break; + } + + if (!ControlAction.makeCharacter(info)) { + // TODO: check if acc is full and cancel location 15 and 29 if true + nextChar(); + + break; + } + + D2Bot.printToConsole("Made character: " + info.charName, 7); + } + + 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 + if (!locationTimeout(StarterConfig.ConnectingTimeout * 1e3, location)) { + ControlAction.click(6, 33, 572, 128, 35); + } + + 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: // game already exists + ControlAction.click(6, 652, 469, 120, 20); // Join + + break; + case 27: // Gateway Select + ControlAction.click(6, 436, 538, 96, 32); + + break; + case 28: // Lobby - Game Does Not Exist + ControlAction.click(6, 533, 469, 120, 20); + + break; + case 30: // charname already exists + ControlAction.click(6, 351, 337, 96, 32); + ControlAction.click(6, 33, 572, 128, 35); + + break; + case 38: // Game is full + break; // not sure how/if to handle + } +} \ No newline at end of file diff --git a/d2bs/kolbot/D2BotMuleLog.dbj b/d2bs/kolbot/D2BotMuleLog.dbj new file mode 100644 index 000000000..73655f8fe --- /dev/null +++ b/d2bs/kolbot/D2BotMuleLog.dbj @@ -0,0 +1,630 @@ +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 + CreateGameDelay: 5, // Seconds to wait before creating a new game + + SwitchKeyDelay: 0, // Seconds to wait before switching a used/banned key or after realm down + + CrashDelay: 60, // Seconds to wait after a d2 window crash + 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. SwitchKeys overrides this! + 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 +}; + + + +// No touchy! +include("json2.js"); +include("OOG.js"); +include("MuleLogger.js"); +include("gambling.js"); +include("common/misc.js"); + +if (!FileTools.exists("data/" + me.profile + ".json")) { + DataFile.create(); +} + +var handle, gameInfo, gameStart, ingame, firstLogin, connectFail, chatActionsDone, currAcc, charList, nextAcc, + lastGameStatus = "ready", + gameCount = DataFile.getStats().runs + 1, + accounts = [], + chars = []; + +function parseInfo() { + var i; + + for (i in MuleLogger.LogAccounts) { + if (MuleLogger.LogAccounts.hasOwnProperty(i) && typeof i === "string") { + accounts.push(i); + chars.push(MuleLogger.LogAccounts[i]); + } + } +} + +function ReceiveCopyData(mode, msg) { + switch (msg) { + case "Handle": + handle = mode; + + break; + } + + switch (mode) { + case 2: // game info + print("Recieved Game Info"); + + gameInfo = JSON.parse(msg); + + break; + case 4: + // Heartbeat ping + if (msg === "pingreq") { + sendCopyData(null, me.windowtitle, 4, "pingrep"); + } + + break; + } +} + +function timeoutDelay(text, time) { + var endTime = getTickCount() + time; + + while (getTickCount() < endTime) { + D2Bot.updateStatus(text + " (" + Math.floor((endTime - getTickCount()) / 1000) + "s)"); + delay(500); + } +} + +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 main() { + addEventListener('copydata', ReceiveCopyData); + + while (!handle) { + delay(100); + } + + DataFile.updateStats("handle", handle); + D2Bot.init(); + load("tools/heartbeat.js"); + + while (!gameInfo) { + D2Bot.requestGameInfo(); + 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) { + 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 + if (!ingame) { + print("Updating Status"); + D2Bot.updateStatus("Game: " + me.gamename); + + lastGameStatus = "ingame"; + ingame = true; + gameStart = getTickCount(); + + DataFile.updateStats("runs", gameCount); + } + } + + delay(1000); + } + + locationAction(getLocation()); + delay(1000); + } +} + +function locationAction(location) { + var i, control, string, text, currChar, + obj = {}; + +MainSwitch: + switch (location) { + case 0: + break; + case 1: // Lobby + case 3: // Lobby Chat + D2Bot.updateStatus("Lobby"); + + if (ingame) { + if (getTickCount() - gameStart < StarterConfig.MinGameTime * 1e3) { + timeoutDelay("Min game time wait", StarterConfig.MinGameTime * 1e3 + gameStart - getTickCount()); + } + + print("updating runs"); + D2Bot.updateRuns(); + delay(1000); + + gameCount += 1; + lastGameStatus = "ready"; + ingame = false; + + ControlAction.click(6, 693, 490, 80, 20); // Quit from Lobby + + break; + } + + if (!ControlAction.click(6, 533, 469, 120, 20)) { // Create + break; + } + + if (!locationTimeout(5000, location)) { // in case join button gets bugged + if (!ControlAction.click(6, 652, 469, 120, 20)) { // Join + break; + } + + if (!ControlAction.click(6, 533, 469, 120, 20)) { // Create + break; + } + } + + break; + case 2: // Waiting In Line + D2Bot.updateStatus("Waiting..."); + locationTimeout(StarterConfig.WaitInLineTimeout * 1e3, location); + ControlAction.click(6, 433, 433, 96, 32); + + break; + case 4: // Create Game + D2Bot.updateStatus("Creating Game"); + + control = getControl(1, 657, 342, 27, 20); + + if (control && control.disabled === 5) { + ControlAction.click(6, 431, 341, 15, 16); // remove level restriction + } + + if (gameCount >= 99) { + gameCount = 1; + + DataFile.updateStats("runs", gameCount); + } + + if (lastGameStatus === "pending") { + D2Bot.printToConsole("Failed to create game"); + + gameCount += 1; + } + + timeoutDelay("Make Game Delay", StarterConfig.CreateGameDelay * 1e3); + createGame(MuleLogger.LogGame[0] + gameCount, MuleLogger.LogGame[1], 0); + locationTimeout(5000, location); + + lastGameStatus = "pending"; + + break; + case 5: // Join Game + break; + case 6: // Ladder + break; + case 7: // Channel List + break; + case 8: // Main Menu + case 9: // Login + case 18: // D2 Splash + if (nextAcc) { + accounts.shift(); + chars.shift(); + + nextAcc = false; + } + + if (!accounts.length) { + FileTools.remove("logs/MuleLog.json"); + D2Bot.printToConsole("Done logging mules!"); + D2Bot.stop(); + + break; + } + + if (FileTools.exists("logs/MuleLog.json")) { + obj = JSON.parse(FileTools.readText("logs/MuleLog.json")); + + if (obj.currAcc) { + for (i = 0; i < accounts.length; i += 1) { + if (accounts[i].split("/")[0] === obj.currAcc) { + accounts.splice(0, i); + chars.splice(0, i); + + i -= 1; + + break; + } + } + } + } + + currAcc = accounts[0]; + currAcc = currAcc.split("/"); + charList = chars[0]; + obj.currAcc = currAcc[0]; + + print("ÿc4Mule Loggerÿc2: Login account: " + currAcc[0]); + FileTools.writeText("logs/MuleLog.json", JSON.stringify(obj)); + ControlAction.loginAccount({account: currAcc[0], password: currAcc[1], realm: currAcc[2]}); + + 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): + 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: " + 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); + + if (gameInfo.switchKeys) { + ControlAction.timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.stop(); + } + + 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) { + timeoutDelay("Unable to Connect", StarterConfig.UnableToConnectDelay * 6e4); + + connectFail = false; + } + + if (!ControlAction.click(6, 335, 450, 128, 35)) { + break; + } + + connectFail = true; + + break; + case 12: // Character Select + // Single Player screen fix + if (getLocation() === 12 && !getControl(4, 626, 100, 151, 44)) { + ControlAction.click(6, 33, 572, 128, 35); + + break; + } + + if (!charList.length) { + ControlAction.click(6, 33, 572, 128, 35); + + break; + } + + if (charList[0] === "all") { + charList = ControlAction.getCharacters(); + } + + if (FileTools.exists("logs/MuleLog.json")) { + obj = JSON.parse(FileTools.readText("logs/MuleLog.json")); + + if (obj.currChar) { + for (i = 0; i < charList.length; i += 1) { + if (charList[i] === obj.currChar) { + charList.splice(0, i + 1); // Remove the previous currChar as well + + break; + } + } + } + } + + // 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}); + + break; + case 13: // Realm Down - Character Select screen + D2Bot.updateStatus("Realm Down"); + delay(1000); + + if (!ControlAction.click(6, 33, 572, 128, 35)) { + break; + } + + updateCount(); + timeoutDelay("Realm Down", StarterConfig.RealmDownDelay * 6e4); + + if (gameInfo.switchKeys) { + D2Bot.printToConsole("Realm Down - Changing CD-Key"); + timeoutDelay("Key switch delay", StarterConfig.SwitchKeyDelay * 1000); + D2Bot.restart(true); + } else { + D2Bot.restart(); + } + + break; + case 14: // Character Select / Main Menu - Disconnected + D2Bot.updateStatus("Disconnected"); + delay(500); + ControlAction.click(6, 351, 337, 96, 32); + break; + case 15: // New Character + 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 + if (!locationTimeout(StarterConfig.ConnectingTimeout * 1e3, location)) { + ControlAction.click(6, 33, 572, 128, 35); + } + + 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); + + break; + case 27: // Gateway Select + ControlAction.click(6, 436, 538, 96, 32); + + break; + case 28: // Lobby - Game Does Not Exist + ControlAction.click(6, 533, 469, 120, 20); + + break; + case 38: // Game is full + D2Bot.printToConsole("Game is full"); + + lastGameStatus = "ready"; + + delay(500); + ControlAction.click(6, 652, 469, 120, 20); + + 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 + + ControlAction.click(6, 33, 572, 128, 35); + } + + break; + default: + if (location !== undefined) { + D2Bot.printToConsole("Unhandled location " + location); + delay(500); + D2Bot.restart(); + } + + break; + } +} diff --git a/d2bs/kolbot/default.dbj b/d2bs/kolbot/default.dbj index 2134abdb3..adc6d0bf9 100644 --- a/d2bs/kolbot/default.dbj +++ b/d2bs/kolbot/default.dbj @@ -4,9 +4,14 @@ 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"); @@ -17,79 +22,127 @@ include("common/Prototypes.js"); include("common/Runewords.js"); include("common/Storage.js"); include("common/Town.js"); - -var gidList = []; // fast pickit +include("common/Enums.js"); function main() { - var i, sojPause, - sojCounter = 0, - startTime = getTickCount(); - - this.dcloneEvent = function (mode, param1, param2, name1, name2) { - switch (mode) { - case 17: // 0x11 - "%Param1 Stones of Jordan Sold to Merchants" - if (!Config.SoJWaitTime) { - break; - } + D2Bot.init(); // Get D2Bot# handle + D2Bot.ingame(); - D2Bot.printToConsole(param1 + " Stones of Jordan Sold to Merchants;7"); - sojPause = true; - sojCounter = 0; + // wait until game is ready + while (!me.gameReady) { + delay(50); + } - break; - case 18: // 0x12 - "Diablo Walks the Earth" - if (!Config.StopOnDClone) { - break; - } + if (!getScript("tools/heartbeat.js")) { + load("tools/heartbeat.js"); + } - D2Bot.printToConsole("Diablo Walks the Earth;7"); - removeEventListener("gameevent", this.dcloneEvent); - scriptBroadcast("dclone"); + if (getScript("d2botmap.dbj")) { + load("tools/mapthread.js"); + load("tools/ToolsThread.js"); - break; + while (true) { + delay(1000); } - }; + } + + // don't load default for mules + if (getScript("D2BotMule.dbj")) { + return true; + } + + // MuleLogger handler + if (MuleLogger.inGameCheck()) { + return true; + } + + var i, sojPause, stats, anni, + sojCounter = 0, + startTime = getTickCount(); this.itemEvent = function (gid, mode, code, global) { if (gid > 0 && mode === 0) { - gidList.push(gid); + Pickit.gidList.push(gid); + } + }; + + this.scriptEvent = function (msg) { + switch (msg) { + case "soj": + sojPause = true; + sojCounter = 0; + + break; } }; - // If game name is a part of Gambling System, don't load scripts - if (Gambling.goldFinders.indexOf(me.profile) > -1) { - for (i = 0; i < Gambling.gambleGames.length; i += 1) { - if (me.gamename.match(Gambling.gambleGames[i])) { - Gambling.dropGold(); - DataFile.updateStats("gold"); - delay(5000); - quit(); + 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(); + Pickit.init(true); Attack.init(); Storage.Init(); - Cubing.init(); + CraftingSystem.buildLists(); Runewords.init(); + Cubing.init(); - me.maxgametime = Config.MaxGameTime * 1000; + // AutoMule handler + if (AutoMule.inGameCheck()) { + return true; + } + + // TorchSystem handler + if (TorchSystem.inGameCheck()) { + return true; + } + + // Gambling System handler + if (Gambling.inGameCheck()) { + return true; + } + + // Crafting System handler + if (CraftingSystem.inGameCheck()) { + return true; + } - if (me.getStat(13) < DataFile.getStats().experience) { // check for experience decrease -> log death - D2Bot.printToConsole("You died in last game;1"); - D2Bot.printToConsole("Experience decreased by " + (DataFile.getStats().experience - me.getStat(13)) + ";1"); - DataFile.updateDeaths(); + me.maxgametime = Config.MaxGameTime * 1000; + stats = DataFile.getStats(); + + // Check for experience decrease -> log death. Skip report if life chicken is disabled. + if (stats.name === me.name && me.getStat(13) < stats.experience && Config.LifeChicken > 0) { + D2Bot.printToConsole("You died in last game", 9); + D2Bot.printToConsole("Experience decreased by " + (stats.experience - me.getStat(13)), 9); + DataFile.updateStats("deaths"); + D2Bot.updateDeaths(); } - DataFile.updateStats("experience"); + DataFile.updateStats(["experience", "name"]); // Load events and threads - addEventListener("gameevent", this.dcloneEvent); + addEventListener("scriptmsg", this.scriptEvent); + addEventListener("copydata", this.copyDataEvent); load("tools/ToolsThread.js"); + if (Config.TownCheck || Config.TownHP || Config.TownMP) { + load("tools/TownChicken.js"); + } + if (Config.PublicMode) { load("tools/Party.js"); } @@ -104,11 +157,18 @@ function main() { } // One time maintenance - get corpse, clear leftover items, pick items in case anything important was dropped - if (!Scripts.UserAddon) { + if (!Scripts.UserAddon && !Scripts.Test) { Town.getCorpse(); Town.clearBelt(); Town.clearInventory(); - Pickit.pickItems(); + //Pickit.pickItems(); + } + + me.automap = Config.AutoMap; + + // Next game = drop keys + if (TorchSystem.keyCheck()) { + scriptBroadcast("torch"); } // Go @@ -127,17 +187,12 @@ function main() { } } - print("ÿc8Run duration ÿc2" + ((getTickCount() - startTime) / 1000)); DataFile.updateStats("gold"); - if (Config.LogExperience) { - delay(500); - Experience.log(); - } - if (sojPause) { try { Town.goToTown(); + Town.doChores(); me.maxgametime = 0; @@ -153,8 +208,40 @@ function main() { } if (Config.LastMessage) { - say(Config.LastMessage); + switch (typeof Config.LastMessage) { + case "string": + say(Config.LastMessage.replace("$nextgame", DataFile.getStats().nextGame, "i")); + + break; + case "object": + for (i = 0; i < Config.LastMessage.length; i += 1) { + say(Config.LastMessage[i].replace("$nextgame", DataFile.getStats().nextGame, "i")); + } + + break; + } + } + + if (AutoMule.muleCheck()) { + scriptBroadcast("mule"); } - quit(); + // 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"); + + return true; } \ No newline at end of file diff --git a/d2bs/kolbot/libs/AutoMule.js b/d2bs/kolbot/libs/AutoMule.js new file mode 100644 index 000000000..b0bed649c --- /dev/null +++ b/d2bs/kolbot/libs/AutoMule.js @@ -0,0 +1,603 @@ +var AutoMule = { + Mules: { + "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. + accountPassword: "", // Account password. + charPrefix: "", // Character prefix. Suffix added automatically when making characters. + realm: "", // Available options: "useast", "uswest", "europe", "asia" + expansion: true, + ladder: true, + hardcore: false, + + // Game name and password of the mule game. Never use the same game name as for mule logger. + muleGameName: ["", ""], // ["gamename", "password"] + + // List of profiles that will mule items. Example: enabledProfiles: ["profile 1", "profile 2"], + enabledProfiles: [""], + + // Stop a profile prior to muling. Useful when running 8 bots without proxies. + stopProfile: "", + + // Trigger muling at the end of a game if used space in stash and inventory is equal to or more than given percent. + usedStashTrigger: 80, + usedInventoryTrigger: 80, + + // Mule items that have been stashed at some point but are no longer in pickit. + muleOrphans: true + } + }, + + /** 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. + accountPassword: "", // Account password. + charPrefix: "", // Character prefix. Suffix added automatically when making characters. + realm: "", // Available options: "useast", "uswest", "europe", "asia" + expansion: true, + ladder: true, + hardcore: false, + + // Game name and password of the mule game. Never use the same game name as for mule logger. + muleGameName: ["", ""], // ["gamename", "password"] + + // List of profiles that will mule items. Example: enabledProfiles: ["profile 1", "profile 2"], + enabledProfiles: [""], + + // Stop a profile prior to muling. Useful when running 8 bots without proxies. + stopProfile: "" + } +//########################################################################################## + }, + + inGame: false, + check: false, + torchAnniCheck: false, + + // *** Master functions *** + getInfo: function () { + var i, j, info; + + for (i in this.Mules) { + if (this.Mules.hasOwnProperty(i)) { + for (j = 0; j < this.Mules[i].enabledProfiles.length; j += 1) { + if (this.Mules[i].enabledProfiles[j].toLowerCase() === me.profile.toLowerCase()) { + if (!info) { + info = {}; + } + + info.muleInfo = this.Mules[i]; + } + } + } + } + + 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.TorchAnniMules[i]; + } + } + } + } + + return info; + }, + + muleCheck: function () { + var info = this.getInfo(); + + if (info && info.hasOwnProperty("muleInfo") && info.muleInfo.hasOwnProperty("usedStashTrigger") && info.muleInfo.hasOwnProperty("usedInventoryTrigger") && + Storage.Inventory.UsedSpacePercent() >= info.muleInfo.usedInventoryTrigger && Storage.Stash.UsedSpacePercent() >= info.muleInfo.usedStashTrigger && + this.getMuleItems().length > 0) { + D2Bot.printToConsole("MuleCheck triggered!", 7); + + return true; + } + + return false; + }, + + getMule: function () { + var info; + + info = this.getInfo(); + + if (info) { + if (this.check && info.hasOwnProperty("muleInfo")) { + return info.muleInfo; + } + + if (this.torchAnniCheck && info.hasOwnProperty("torchMuleInfo")) { + return info.torchMuleInfo; + } + } + + return false; + }, + + outOfGameCheck: function () { + if (!this.check && !this.torchAnniCheck) { + return false; + } + + var i, control, muleObj, + stopCheck = false, + muleInfo = {status: ""}, + failCount = 0; + + muleObj = this.getMule(); + + if (!muleObj) { + return false; + } + + function MuleCheckEvent(mode, msg) { + if (mode === 10) { + muleInfo = JSON.parse(msg); + } + } + + addEventListener("copydata", MuleCheckEvent); + 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.torchAnniCheck || 0}))) { + D2Bot.start(muleObj.muleProfile); + } + + delay(1000); + + switch (muleInfo.status) { + case "loading": + if (!stopCheck && muleObj.stopProfile && me.profile.toLowerCase() !== muleObj.stopProfile.toLowerCase()) { + D2Bot.stop(muleObj.stopProfile); + + stopCheck = true; + } + + failCount += 1; + + break; + case "busy": + case "begin": + D2Bot.printToConsole("Mule profile is busy.", 9); + + break MainLoop; + case "ready": + control = getControl(6, 652, 469, 120, 20); + + if (control) { + delay(200); + control.click(); + } + + delay(2000); + + this.inGame = true; + me.blockMouse = true; + + try { + joinGame(muleObj.muleGameName[0], muleObj.muleGameName[1]); + } catch (joinError) { + + } + + me.blockMouse = false; + + // Untested change 11.Feb.14. + for (i = 0; i < 8; i += 1) { + delay(1000); + + if (me.ingame && me.gameReady) { + break MainLoop; + } + } + + break; + default: + failCount += 1; + + break; + } + + if (failCount >= 60) { + D2Bot.printToConsole("No response from mule profile.", 9); + + break; + } + } + + removeEventListener("copydata", MuleCheckEvent); + + while (me.ingame) { + delay(1000); + } + + this.inGame = false; + this.check = false; + this.torchAnniCheck = false; + + // No response - stop mule profile + if (failCount >= 60) { + D2Bot.stop(muleObj.muleProfile); + delay(1000); + } + + if (stopCheck && muleObj.stopProfile) { + D2Bot.start(muleObj.stopProfile); + } + + return true; + }, + + inGameCheck: function () { + var muleObj, tick, info, + timeout = 150 * 1000, // Ingame mule timeout + status = "muling"; + + // Single player + if (!me.gamename) { + return false; + } + + info = this.getInfo(); + + // Profile is not a part of AutoMule + if (!info) { + return false; + } + + // Profile is not in mule or torch mule game + if (!((info.hasOwnProperty("muleInfo") && me.gamename.toLowerCase() === info.muleInfo.muleGameName[0].toLowerCase()) || + (info.hasOwnProperty("torchMuleInfo") && me.gamename.toLowerCase() === info.torchMuleInfo.muleGameName[0].toLowerCase()))) { + return false; + } + + function DropStatusEvent(mode, msg) { + if (mode === 10) { + switch (JSON.parse(msg).status) { + case "report": // reply to status request + sendCopyData(null, muleObj.muleProfile, 12, JSON.stringify({status: status})); + + break; + case "quit": // quit command + status = "quit"; + + break; + } + } + } + + function MuleModeEvent(msg) { + switch (msg) { + case "2": + AutoMule.torchAnniCheck = 2; + + break; + case "1": + AutoMule.torchAnniCheck = 1; + + break; + case "0": + AutoMule.check = true; + + break; + } + } + + addEventListener("copydata", DropStatusEvent); + addEventListener("scriptmsg", MuleModeEvent); + scriptBroadcast("getMuleMode"); + delay(500); + + if (!this.check && !this.torchAnniCheck) { + print("Error - Unable to determine mule mode"); + quit(); + + return false; + } + + muleObj = this.getMule(); + me.maxgametime = 0; + + if (!Town.goToTown(1)) { + print("Error - Failed to go to Act 1"); + quit(); + + return false; + } + + sendCopyData(null, muleObj.muleProfile, 11, "begin"); + + 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.updateStatus("AutoMule: In game."); + this.dropCharm(false); + } else { + print("ÿc4AutoMuleÿc0: In mule game."); + D2Bot.updateStatus("AutoMule: In game."); + this.dropStuff(); + } + + status = "done"; + tick = getTickCount(); + + while (true) { + if (status === "quit") { + break; + } + + 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; + } + + delay(500); + } + + removeEventListener("copydata", DropStatusEvent); + D2Bot.stop(muleObj.muleProfile); + delay(1000); + + if (muleObj.stopProfile) { + D2Bot.start(muleObj.stopProfile); + } + + if (getScript("AnniStarter.dbj")) { + scriptBroadcast("exit"); + } + + delay(2000); + quit(); + //delay(10000); + + return true; + }, + + dropStuff: function () { + if (!Town.openStash()) { + return false; + } + + 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(); + } + + delay(1000); + me.cancel(); + + return true; + }, + + // get a list of items to mule + getMuleItems: function () { + var item, items, info; + + info = this.getInfo(); + + if (!info || !info.hasOwnProperty("muleInfo")) { + return false; + } + + item = me.getItem(-1, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); + items = []; + + + if (item) { + do { + if (Town.ignoredItemTypes.indexOf(item.itemType) === -1 && + (Pickit.checkItem(item).result > 0 || (item.location === ItemLocation.Stash && info.muleInfo.hasOwnProperty("muleOrphans") && info.muleInfo.muleOrphans)) && + item.classid !== ItemClassIds.Horadric_Cube && // Don't drop Horadric Cube + (item.classid !== ItemClassIds.Small_Charm || item.quality !== ItemQuality.Unique) && // Don't drop Annihilus + (item.classid !== ItemClassIds.Large_Charm || item.quality !== ItemQuality.Unique) && // Don't drop Hellfire Torch + (item.location === ItemLocation.Stash || (item.location === ItemLocation.Inventory && !Storage.Inventory.IsLocked(item, Config.Inventory))) && // Don't drop items in locked slots + ((!TorchSystem.getFarmers() && !TorchSystem.isFarmer()) || [ItemClassIds.Key_Of_Terror, ItemClassIds.Key_Of_Hate, ItemClassIds.Key_Of_Destruction].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()); + } + + 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; + + for (i = 0; i < Cubing.validIngredients.length; i += 1) { + if (item.gid === Cubing.validIngredients[i].gid) { + return true; + } + } + + return false; + }, + + // check if an item is a runeword ingrediend - rune, empty base or bad rolled base + runewordIngredient: function (item) { + if (Runewords.validGids.indexOf(item.gid) > -1) { + return true; + } + + if (!this.baseGids) { + var i, base; + + this.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) { + this.baseGids.push(base.gid); + } + } + } + + if (this.baseGids.indexOf(item.gid) > -1) { + return true; + } + + return false; + }, + + dropCharm: function (dropAnni) { + if (!Town.openStash()) { + return false; + } + + var item; + + if (dropAnni) { + item = me.findItem(ItemClassIds.Small_Charm, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, -1, ItemQuality.Unique); + + 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(ItemClassIds.Large_Charm, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, -1, ItemQuality.Unique); + + if (item) { + D2Bot.printToConsole("AutoMule: Transfering Torch.", 7); + item.drop(); + delay(1000); + me.cancel(); + + return true; + } + + me.cancel(); + + return true; + }, + + // *** Mule functions *** + getMaster: function (info) { + var i, j, k, muleObj; + + muleObj = info.mode === 1 ? this.TorchAnniMules : this.Mules; + + for (i in muleObj) { + if (muleObj.hasOwnProperty(i)) { + for (j in muleObj[i]) { + if (muleObj[i].hasOwnProperty(j) && j === "enabledProfiles") { + for (k = 0; k < muleObj[i][j].length; k += 1) { + if (muleObj[i][j][k].toLowerCase() === info.profile.toLowerCase()) { + return { + profile: muleObj[i][j][k], + mode: info.mode + }; + } + } + } + } + } + } + + return false; + }, + + getMuleObject: function (mode, master) { + var i, mule; + + mode = mode || 0; + mule = mode > 0 ? this.TorchAnniMules : this.Mules; + + for (i in mule) { + if (mule.hasOwnProperty(i)) { + if (mule[i].muleProfile && mule[i].enabledProfiles && + mule[i].muleProfile.toLowerCase() === me.profile.toLowerCase() && mule[i].enabledProfiles.indexOf(master) > -1) { + return mule[i]; + } + } + } + + return false; + }, + + getMuleFilename: function (mode, master) { + var i, mule, jsonObj, jsonStr, file; + + mode = mode || 0; + 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() && mule[i].enabledProfiles.indexOf(master) > -1) { + file = mode === 0 ? "logs/AutoMule." + i + ".json" : "logs/TorchMule." + i + ".json"; + + // If file exists check for valid info + if (FileTools.exists(file)) { + try { + jsonStr = FileTools.readText(file); + jsonObj = JSON.parse(jsonStr); + + // Return filename containing correct mule info + if (mule[i].accountPrefix && jsonObj.account && jsonObj.account.match(mule[i].accountPrefix)) { + return file; + } + } catch (e) { + print(e); + } + } else { + return file; + } + } + } + } + + // File exists but doesn't contain valid info - remake + FileTools.remove(file); + + return file; + } +}; \ No newline at end of file diff --git a/d2bs/kolbot/libs/CraftingSystem.js b/d2bs/kolbot/libs/CraftingSystem.js new file mode 100644 index 000000000..933c97479 --- /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 NTItemTypes.jewel: // 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 === ItemQuality.Crafted) { // 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, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); + + 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 ItemClassIds.Perfect_Amethyst: // Pgems + case ItemClassIds.Perfect_Topaz: + case ItemClassIds.Perfect_Sapphire: + case ItemClassIds.Perfect_Emerald: + case ItemClassIds.Perfect_Ruby: + case ItemClassIds.Perfect_Diamond: + case ItemClassIds.Perfect_Skull: + 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(Stats.gold) >= 10000) { + gold(10000); + } else if (me.getStat(Stats.goldbank) + me.getStat(Stats.gold) >= 10000) { + Town.openStash(); + gold(10000 - me.getStat(Stats.gold), 4); + gold(10000); + } +}; \ No newline at end of file diff --git a/d2bs/kolbot/libs/Gambling.js b/d2bs/kolbot/libs/Gambling.js index 872770809..b7fde279d 100644 --- a/d2bs/kolbot/libs/Gambling.js +++ b/d2bs/kolbot/libs/Gambling.js @@ -5,94 +5,191 @@ */ var Gambling = { - /* -#################################################################################################### - Gambling system for kolbot + Teams: { +//#################################################################################################### + /* Gambling system for kolbot - Allows lower level characters to get a steady income of gold to gamble LLD/VLLD items - Not recommended for rings/amulets because of their high price (unless you want 3 gold finders to supply one gambler) + Allows lower level characters to get a steady income of gold to gamble LLD/VLLD items + Not recommended for rings/amulets because of their high price (unless you want 3 gold finders to supply one gambler) + It's possible to have multiple teams of gamblers/gold finders. Individual entries are separated by commas. - Setting up: + Setting up: - * goldFinders = PROFILE NAMES that will enter games and drop gold (profile names match window titles) - example: goldFinders: ["GF 1", "GF 2"], // don't remove the comma + "Gamble Team 1": { // Put a unique team name here. - * gamblers = PROFILE NAMES that gamble and pick up gold dropped by gold finders - example: gamblers: ["Gamble 1", "Gamble 2"], // don't remove the comma + goldFinders: ["GF Profile 1", "GF Profile 2"], // List of gold finder PROFILE names. They will join gamble games to drop gold - * gambleGames = games that gold finders will join, don't use numbers. NOTE: d2 always makes first letter of game name uppercase - example: gambleGames: ["Gamble1-", "Gamble2-"], // don't remove the comma + gamblers: ["Gambler 1", "Gambler 2"], // List of gambler PROFILE names. They will keep gambling and picking up gold from gold finders. - * minGold = min amount to keep when dropping gold - example: minGold: 150000, // don't remove the comma - - Once set up properly, the gold finders will run their own games and join gamblers' games when they're out of gold. - */ + gambleGames: ["Gambling-", "HeyIGamble-"], // Games that gold finders will join, don't use numbers. - goldFinders: [""], // don't remove the comma - gamblers: [""], // don't remove the comma - gambleGames: [""], // don't remove the comma + goldTrigger: 2500000, // Minimum amount of gold before giving it to gamblers. - minGold: 200000, // don't remove the comma + goldReserve: 200000 // Amount of gold to keep after dropping. + } + + Once set up properly, the gold finders will run their own games and join gamblers' games when they're out of gold. + */ + + "Gamble Team 1": { + goldFinders: [""], + gamblers: [""], + gambleGames: [""], + + goldTrigger: 2500000, + goldReserve: 200000 + } + +//#################################################################################################### + }, + + inGame: false, + + getInfo: function (profile) { + var i, j; + + if (!profile) { + profile = me.profile; + } + + for (i in this.Teams) { + if (this.Teams.hasOwnProperty(i)) { + for (j = 0; j < this.Teams[i].goldFinders.length; j += 1) { + if (this.Teams[i].goldFinders[j].toLowerCase() === profile.toLowerCase()) { + this.Teams[i].goldFinder = true; + this.Teams[i].gambler = false; + + return this.Teams[i]; + } + } + + for (j = 0; j < this.Teams[i].gamblers.length; j += 1) { + if (this.Teams[i].gamblers[j].toLowerCase() === profile.toLowerCase()) { + this.Teams[i].goldFinder = false; + this.Teams[i].gambler = true; + + return this.Teams[i]; + } + } + } + } + + return false; + }, + + inGameCheck: function () { + var i, + info = this.getInfo(); + + if (info && info.goldFinder) { + for (i = 0; i < info.gambleGames.length; i += 1) { + if (info.gambleGames[i] && me.gamename.match(info.gambleGames[i], "i")) { + this.dropGold(); + DataFile.updateStats("gold"); + delay(5000); + quit(); + //delay(10000); + + return true; + } + } + } - /* -#################################################################################################### - Internals, don't edit unless you know how to - */ + return false; + }, dropGold: function () { - Town.goToTown(1); - Town.move("stash"); + var info = this.getInfo(); - while (me.getStat(14) + me.getStat(15) > this.minGold) { - gold(me.getStat(14)); // drop current gold - Town.openStash(); + if (info && info.goldFinder) { + Town.goToTown(1); + Town.move("stash"); - if (me.getStat(15) <= me.getStat(12) * 1e4) { // check stashed gold vs max carrying capacity - gold(me.getStat(15) - this.minGold, 4); // leave minGold in stash, pick the rest - } else { - gold(me.getStat(12) * 1e4, 4); // pick max carrying capacity + while (me.getStat(Stats.gold) + me.getStat(Stats.goldbank) > info.goldReserve) { + gold(me.getStat(Stats.gold)); // drop current gold + Town.openStash(); + + if (me.getStat(Stats.goldbank) <= me.getStat(Stats.level) * 1e4) { // check stashed gold vs max carrying capacity + gold(me.getStat(Stats.goldbank) - info.goldReserve, 4); // leave minGold in stash, pick the rest + } else { + gold(me.getStat(Stats.level) * 1e4, 4); // pick max carrying capacity + } + + delay(1000); } + } + }, + + outOfGameCheck: function () { + var game, + info = this.getInfo(); + + if (info && info.goldFinder && DataFile.getStats().gold >= info.goldTrigger) { + game = this.getGame(); + + if (game) { + D2Bot.printToConsole("Joining gold drop game.", 7); + + this.inGame = true; + me.blockMouse = true; + + delay(2000); + joinGame(game[0], game[1]); + + me.blockMouse = false; - delay(1000); + delay(5000); + + while (me.ingame) { + delay(1000); + } + + this.inGame = false; + + return true; + } } + + return false; }, - checkGamblers: function () { - if (this.goldFinders.indexOf(me.profile) === -1) { + getGame: function () { + var i, game, + info = this.getInfo(); + + if (!info || !info.goldFinder) { return false; } function CheckEvent(mode, msg) { var i; - for (i = 0; i < Gambling.gambleGames.length; i += 1) { - if (msg.match(Gambling.gambleGames[i])) { - game = msg.split('/'); + if (mode === 4) { + for (i = 0; i < info.gambleGames.length; i += 1) { + if (info.gambleGames[i] && msg.match(info.gambleGames[i], "i")) { + game = msg.split('/'); - break; + break; + } } } - - removeEventListener('copydata', CheckEvent); - - return true; } - var i, game; - addEventListener('copydata', CheckEvent); + game = null; - for (i = 0; i < this.gamblers.length; i += 1) { - sendCopyData(null, this.gamblers[i], 0, me.profile); + for (i = 0; i < info.gamblers.length; i += 1) { + sendCopyData(null, info.gamblers[i], 0, me.profile); delay(100); if (game) { - return game; + break; } } - return false; + removeEventListener('copydata', CheckEvent); + + return game; } }; \ No newline at end of file diff --git a/d2bs/kolbot/libs/MuleLogger.js b/d2bs/kolbot/libs/MuleLogger.js new file mode 100644 index 000000000..eb4f137b3 --- /dev/null +++ b/d2bs/kolbot/libs/MuleLogger.js @@ -0,0 +1,374 @@ +/** +* @filename MuleLogger.js +* @author kolton +* @desc Log items on configurable accounts/characters +*/ + +var MuleLogger = { + LogAccounts: { + /* Format: + "account1/password1/realm": ["charname1", "charname2 etc"], + "account2/password2/realm": ["charnameX", "charnameY etc"], + "account3/password3/realm": ["all"] + + To log a full account, put "accountname/password/realm": ["all"] + + realm = useast, uswest, europe or asia + + Individual entries are separated with a comma. + */ + + "account/password/realm": ["all"] + }, + + LogGame: ["", ""], // ["gamename", "password"] + LogNames: true, // Put account/character name on the picture + LogItemLevel: true, // Add item level to the picture + LogEquipped: false, // include equipped items + LogMerc: false, // include items merc has equipped (if alive) + SaveScreenShot: false, // Save pictures in jpg format (saved in 'Images' folder) + IngameTime: 20, // Time to wait after leaving game + + // don't edit + 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. + for (i = 0; i < desc.length; i += 1) { + if (desc[i].indexOf(getLocaleString(3331)) > -1) { // Remove sell value + desc.splice(i, 1); + + i -= 1; + } else { + if (desc[i].match(/^(y|ÿ)c/)) { + stringColor = desc[i].substring(0, 3); + } else { + desc[i] = stringColor + desc[i]; + } + } + + desc[i] = desc[i].replace(/(y|ÿ)c([0-9!"+<;.*])/g, "\\xffc$2").replace("\xFF", "\\xff", "g"); + } + + if (logIlvl && desc[desc.length - 1]) { + desc[desc.length - 1] = desc[desc.length - 1].trim() + " (" + unit.ilvl + ")"; + } + + desc = desc.reverse().join("\\n"); + + return desc; + }, + + inGameCheck: function () { + if (getScript("D2BotMuleLog.dbj") && this.LogGame[0] && me.gamename.match(this.LogGame[0], "i")) { + print("ÿc4MuleLoggerÿc0: Logging items on " + me.name + "."); + D2Bot.printToConsole("MuleLogger: Logging items on " + me.name + ".", 7); + this.logChar(); + + while ((getTickCount() - me.gamestarttime) < this.IngameTime * 1000) { + delay(1000); + } + + quit(); + //delay(10000); + + return true; + } + + return false; + }, + + // Log kept item stats in the manager. + 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.itemType + "_" + unit.fname.split("\n").reverse().join(" ").replace(/(y|ÿ)c[0-9!"+<;.*]/, "").trim(); + + desc = this.getItemDesc(unit, logIlvl) + "$" + unit.gid; + color = unit.getColor(); + + switch (unit.quality) { + case 5: // Set + switch (unit.classid) { + case 27: // Angelic sabre + code = "inv9sbu"; + + break; + case 74: // Arctic short war bow + code = "invswbu"; + + break; + case 308: // Berserker's helm + code = "invhlmu"; + + break; + case 330: // Civerb's large shield + code = "invlrgu"; + + break; + case 31: // Cleglaw's long sword + case 227: // Szabi's cryptic sword + code = "invlsdu"; + + break; + case 329: // Cleglaw's small shield + code = "invsmlu"; + + break; + case 328: // Hsaru's buckler + code = "invbucu"; + + break; + case 306: // Infernal cap / Sander's cap + code = "invcapu"; + + break; + case 30: // Isenhart's broad sword + code = "invbsdu"; + + break; + case 309: // Isenhart's full helm + code = "invfhlu"; + + break; + case 333: // Isenhart's gothic shield + code = "invgtsu"; + + break; + case 326: // Milabrega's ancient armor + case 442: // Immortal King's sacred armor + code = "invaaru"; + + break; + case 331: // Milabrega's kite shield + code = "invkitu"; + + break; + case 332: // Sigon's tower shield + code = "invtowu"; + + break; + case 325: // Tancred's full plate mail + code = "invfulu"; + + break; + case 3: // Tancred's military pick + code = "invmpiu"; + + break; + case 113: // Aldur's jagged star + code = "invmstu"; + + break; + case 234: // Bul-Kathos' colossus blade + code = "invgsdu"; + + break; + case 372: // Grizwold's ornate plate + code = "invxaru"; + + break; + case 366: // Heaven's cuirass + case 215: // Heaven's reinforced mace + case 449: // Heaven's ward + case 426: // Heaven's spired helm + code = "inv" + unit.code + "s"; + + break; + case 357: // Hwanin's grand crown + code = "invxrnu"; + + break; + case 195: // Nalya's scissors suwayyah + code = "invskru"; + + break; + case 395: // Nalya's grim helm + case 465: // Trang-Oul's bone visage + code = "invbhmu"; + + break; + case 261: // Naj's elder staff + code = "invcstu"; + + break; + case 375: // Orphan's round shield + code = "invxmlu"; + + break; + case 12: // Sander's bone wand + code = "invbwnu"; + + break; + } + + break; + case 7: // Unique + for (i = 0; i < 401; i += 1) { + if (unit.fname.split("\n").reverse()[0].indexOf(getLocaleString(getBaseStat(17, i, 2))) > -1) { + code = getBaseStat(17, i, "invfile"); + + break; + } + } + + break; + } + + if (!code) { + if (["ci2", "ci3"].indexOf(unit.code) > -1) { // Tiara/Diadem + code = unit.code; + } else { + code = getBaseStat(0, unit.classid, 'normcode') || unit.code; + } + + code = code.replace(" ", ""); + + if ([10, 12, 58, 82, 83, 84].indexOf(unit.itemType) > -1) { + code += (unit.gfx + 1); + } + } + + sock = unit.getItems(); + + if (sock) { + for (i = 0; i < sock.length; i += 1) { + if (sock[i].itemType === 58) { + desc += "\n\n"; + desc += this.getItemDesc(sock[i]); + } + } + } + + return { + itemColor: color, + image: code, + title: name, + description: desc, + header: header, + sockets: Misc.getItemSockets(unit) + }; + }, + + logChar: function (logIlvl, logName, saveImg) { + while (!me.gameReady) { + 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, + items = me.getItems(), + realm = me.realm || "Single Player", + merc, + finalString = ""; + + if (!FileTools.exists("mules/" + realm)) { + folder = dopen("mules"); + + folder.create(realm); + } + + if (!FileTools.exists("mules/" + realm + "/" + me.account)) { + folder = dopen("mules/" + realm); + + folder.create(me.account); + } + + if (!items || !items.length) { + 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], 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)"; + } + + string = JSON.stringify(parsedItem); + finalString += (string + "\n"); + } + } + + 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"); + + if (this.SaveScreenShot) { + D2Bot.saveItem(parsedItem); + } + } + } + } + + 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 f3f9080c5..e9e4a470a 100644 --- a/d2bs/kolbot/libs/NTItemAlias.dbl +++ b/d2bs/kolbot/libs/NTItemAlias.dbl @@ -1,1434 +1,1457 @@ -var _NTIPAliasType = new Array(); -_NTIPAliasType["shield"]=2; -_NTIPAliasType["armor"]=3; -_NTIPAliasType["gold"]=4; -_NTIPAliasType["bowquiver"]=5; -_NTIPAliasType["crossbowquiver"]=6; -_NTIPAliasType["playerbodypart"]=7; -_NTIPAliasType["herb"]=8; -_NTIPAliasType["potion"]=9; -_NTIPAliasType["ring"]=10; -_NTIPAliasType["elixir"]=11; -_NTIPAliasType["amulet"]=12; -_NTIPAliasType["charm"]=13; -_NTIPAliasType["notused"]=14; -_NTIPAliasType["boots"]=15; -_NTIPAliasType["gloves"]=16; -_NTIPAliasType["notused"]=17; -_NTIPAliasType["book"]=18; -_NTIPAliasType["belt"]=19; -_NTIPAliasType["gem"]=20; -_NTIPAliasType["torch"]=21; -_NTIPAliasType["scroll"]=22; -_NTIPAliasType["notused"]=23; -_NTIPAliasType["scepter"]=24; -_NTIPAliasType["wand"]=25; -_NTIPAliasType["staff"]=26; -_NTIPAliasType["bow"]=27; -_NTIPAliasType["axe"]=28; -_NTIPAliasType["club"]=29; -_NTIPAliasType["sword"]=30; -_NTIPAliasType["hammer"]=31; -_NTIPAliasType["knife"]=32; -_NTIPAliasType["spear"]=33; -_NTIPAliasType["polearm"]=34; -_NTIPAliasType["crossbow"]=35; -_NTIPAliasType["mace"]=36; -_NTIPAliasType["helm"]=37; -_NTIPAliasType["missilepotion"]=38; -_NTIPAliasType["quest"]=39; -_NTIPAliasType["bodypart"]=40; -_NTIPAliasType["key"]=41; -_NTIPAliasType["throwingknife"]=42; -_NTIPAliasType["throwingaxe"]=43; -_NTIPAliasType["javelin"]=44; -_NTIPAliasType["weapon"]=45; -_NTIPAliasType["meleeweapon"]=46; -_NTIPAliasType["missileweapon"]=47; -_NTIPAliasType["thrownweapon"]=48; -_NTIPAliasType["comboweapon"]=49; -_NTIPAliasType["anyarmor"]=50; -_NTIPAliasType["anyshield"]=51; -_NTIPAliasType["miscellaneous"]=52; -_NTIPAliasType["socketfiller"]=53; -_NTIPAliasType["secondhand"]=54; -_NTIPAliasType["stavesandrods"]=55; -_NTIPAliasType["missile"]=56; -_NTIPAliasType["blunt"]=57; -_NTIPAliasType["jewel"]=58; -_NTIPAliasType["classspecific"]=59; -_NTIPAliasType["amazonitem"]=60; -_NTIPAliasType["barbarianitem"]=61; -_NTIPAliasType["necromanceritem"]=62; -_NTIPAliasType["paladinitem"]=63; -_NTIPAliasType["sorceressitem"]=64; -_NTIPAliasType["assassinitem"]=65; -_NTIPAliasType["druiditem"]=66; -_NTIPAliasType["handtohand"]=67; -_NTIPAliasType["orb"]=68; -_NTIPAliasType["voodooheads"]=69; -_NTIPAliasType["auricshields"]=70; -_NTIPAliasType["primalhelm"]=71; -_NTIPAliasType["pelt"]=72; -_NTIPAliasType["cloak"]=73; -_NTIPAliasType["rune"]=74; -_NTIPAliasType["circlet"]=75; -_NTIPAliasType["healingpotion"]=76; -_NTIPAliasType["manapotion"]=77; -_NTIPAliasType["rejuvpotion"]=78; -_NTIPAliasType["staminapotion"]=79; -_NTIPAliasType["antidotepotion"]=80; -_NTIPAliasType["thawingpotion"]=81; -_NTIPAliasType["smallcharm"]=82; -_NTIPAliasType["mediumcharm"]=83; -_NTIPAliasType["largecharm"]=84; -_NTIPAliasType["amazonbow"]=85; -_NTIPAliasType["amazonspear"]=86; -_NTIPAliasType["amazonjavelin"]=87; -_NTIPAliasType["assassinclaw"]=88; -_NTIPAliasType["magicbowquiv"]=89; -_NTIPAliasType["magicxbowquiv"]=90; -_NTIPAliasType["chippedgem"]=91; -_NTIPAliasType["flawedgem"]=92; -_NTIPAliasType["standardgem"]=93; -_NTIPAliasType["flawlessgem"]=94; -_NTIPAliasType["perfectgem"]=95; -_NTIPAliasType["amethyst"]=96; -_NTIPAliasType["diamond"]=97; -_NTIPAliasType["emerald"]=98; -_NTIPAliasType["ruby"]=99; -_NTIPAliasType["sapphire"]=100; -_NTIPAliasType["topaz"]=101; -_NTIPAliasType["skull"]=102; +var NTIPAliasType = {}; +NTIPAliasType["shield"] = 2; +NTIPAliasType["armor"] = 3; +NTIPAliasType["gold"] = 4; +NTIPAliasType["bowquiver"] = 5; +NTIPAliasType["crossbowquiver"] = 6; +NTIPAliasType["playerbodypart"] = 7; +NTIPAliasType["herb"] = 8; +NTIPAliasType["potion"] = 9; +NTIPAliasType["ring"] = 10; +NTIPAliasType["elixir"] = 11; +NTIPAliasType["amulet"] = 12; +NTIPAliasType["charm"] = 13; +NTIPAliasType["notused"] = 14; +NTIPAliasType["boots"] = 15; +NTIPAliasType["gloves"] = 16; +NTIPAliasType["notused"] = 17; +NTIPAliasType["book"] = 18; +NTIPAliasType["belt"] = 19; +NTIPAliasType["gem"] = 20; +NTIPAliasType["torch"] = 21; +NTIPAliasType["scroll"] = 22; +NTIPAliasType["notused"] = 23; +NTIPAliasType["scepter"] = 24; +NTIPAliasType["wand"] = 25; +NTIPAliasType["staff"] = 26; +NTIPAliasType["bow"] = 27; +NTIPAliasType["axe"] = 28; +NTIPAliasType["club"] = 29; +NTIPAliasType["sword"] = 30; +NTIPAliasType["hammer"] = 31; +NTIPAliasType["knife"] = 32; +NTIPAliasType["spear"] = 33; +NTIPAliasType["polearm"] = 34; +NTIPAliasType["crossbow"] = 35; +NTIPAliasType["mace"] = 36; +NTIPAliasType["helm"] = 37; +NTIPAliasType["missilepotion"] = 38; +NTIPAliasType["quest"] = 39; +NTIPAliasType["bodypart"] = 40; +NTIPAliasType["key"] = 41; +NTIPAliasType["throwingknife"] = 42; +NTIPAliasType["throwingaxe"] = 43; +NTIPAliasType["javelin"] = 44; +NTIPAliasType["weapon"] = 45; +NTIPAliasType["meleeweapon"] = 46; +NTIPAliasType["missileweapon"] = 47; +NTIPAliasType["thrownweapon"] = 48; +NTIPAliasType["comboweapon"] = 49; +NTIPAliasType["anyarmor"] = 50; +NTIPAliasType["anyshield"] = 51; +NTIPAliasType["miscellaneous"] = 52; +NTIPAliasType["socketfiller"] = 53; +NTIPAliasType["secondhand"] = 54; +NTIPAliasType["stavesandrods"] = 55; +NTIPAliasType["missile"] = 56; +NTIPAliasType["blunt"] = 57; +NTIPAliasType["jewel"] = 58; +NTIPAliasType["classspecific"] = 59; +NTIPAliasType["amazonitem"] = 60; +NTIPAliasType["barbarianitem"] = 61; +NTIPAliasType["necromanceritem"] = 62; +NTIPAliasType["paladinitem"] = 63; +NTIPAliasType["sorceressitem"] = 64; +NTIPAliasType["assassinitem"] = 65; +NTIPAliasType["druiditem"] = 66; +NTIPAliasType["handtohand"] = 67; +NTIPAliasType["orb"] = 68; +NTIPAliasType["voodooheads"] = 69; +NTIPAliasType["auricshields"] = 70; +NTIPAliasType["primalhelm"] = 71; +NTIPAliasType["pelt"] = 72; +NTIPAliasType["cloak"] = 73; +NTIPAliasType["rune"] = 74; +NTIPAliasType["circlet"] = 75; +NTIPAliasType["healingpotion"] = 76; +NTIPAliasType["manapotion"] = 77; +NTIPAliasType["rejuvpotion"] = 78; +NTIPAliasType["staminapotion"] = 79; +NTIPAliasType["antidotepotion"] = 80; +NTIPAliasType["thawingpotion"] = 81; +NTIPAliasType["smallcharm"] = 82; +NTIPAliasType["mediumcharm"] = 83; +NTIPAliasType["largecharm"] = 84; +NTIPAliasType["amazonbow"] = 85; +NTIPAliasType["amazonspear"] = 86; +NTIPAliasType["amazonjavelin"] = 87; +NTIPAliasType["assassinclaw"] = 88; +NTIPAliasType["magicbowquiv"] = 89; +NTIPAliasType["magicxbowquiv"] = 90; +NTIPAliasType["chippedgem"] = 91; +NTIPAliasType["flawedgem"] = 92; +NTIPAliasType["standardgem"] = 93; +NTIPAliasType["flawlessgem"] = 94; +NTIPAliasType["perfectgem"] = 95; +NTIPAliasType["amethyst"] = 96; +NTIPAliasType["diamond"] = 97; +NTIPAliasType["emerald"] = 98; +NTIPAliasType["ruby"] = 99; +NTIPAliasType["sapphire"] = 100; +NTIPAliasType["topaz"] = 101; +NTIPAliasType["skull"] = 102; -var _NTIPAliasClassID = new Array(); -_NTIPAliasClassID["hax"]=0; _NTIPAliasClassID["handaxe"]=0; -_NTIPAliasClassID["axe"]=1; -_NTIPAliasClassID["2ax"]=2; _NTIPAliasClassID["doubleaxe"]=2; -_NTIPAliasClassID["mpi"]=3; _NTIPAliasClassID["militarypick"]=3; -_NTIPAliasClassID["wax"]=4; _NTIPAliasClassID["waraxe"]=4; -_NTIPAliasClassID["lax"]=5; _NTIPAliasClassID["largeaxe"]=5; -_NTIPAliasClassID["bax"]=6; _NTIPAliasClassID["broadaxe"]=6; -_NTIPAliasClassID["btx"]=7; _NTIPAliasClassID["battleaxe"]=7; -_NTIPAliasClassID["gax"]=8; _NTIPAliasClassID["greataxe"]=8; -_NTIPAliasClassID["gix"]=9; _NTIPAliasClassID["giantaxe"]=9; -_NTIPAliasClassID["wnd"]=10; _NTIPAliasClassID["wand"]=10; -_NTIPAliasClassID["ywn"]=11; _NTIPAliasClassID["yewwand"]=11; -_NTIPAliasClassID["bwn"]=12; _NTIPAliasClassID["bonewand"]=12; -_NTIPAliasClassID["gwn"]=13; _NTIPAliasClassID["grimwand"]=13; -_NTIPAliasClassID["clb"]=14; _NTIPAliasClassID["club"]=14; -_NTIPAliasClassID["scp"]=15; _NTIPAliasClassID["scepter"]=15; -_NTIPAliasClassID["gsc"]=16; _NTIPAliasClassID["grandscepter"]=16; -_NTIPAliasClassID["wsp"]=17; _NTIPAliasClassID["warscepter"]=17; -_NTIPAliasClassID["spc"]=18; _NTIPAliasClassID["spikedclub"]=18; -_NTIPAliasClassID["mac"]=19; _NTIPAliasClassID["mace"]=19; -_NTIPAliasClassID["mst"]=20; _NTIPAliasClassID["morningstar"]=20; -_NTIPAliasClassID["fla"]=21; _NTIPAliasClassID["flail"]=21; -_NTIPAliasClassID["whm"]=22; _NTIPAliasClassID["warhammer"]=22; -_NTIPAliasClassID["mau"]=23; _NTIPAliasClassID["maul"]=23; -_NTIPAliasClassID["gma"]=24; _NTIPAliasClassID["greatmaul"]=24; -_NTIPAliasClassID["ssd"]=25; _NTIPAliasClassID["shortsword"]=25; -_NTIPAliasClassID["scm"]=26; _NTIPAliasClassID["scimitar"]=26; -_NTIPAliasClassID["sbr"]=27; _NTIPAliasClassID["sabre"]=27; -_NTIPAliasClassID["flc"]=28; _NTIPAliasClassID["falchion"]=28; -_NTIPAliasClassID["crs"]=29; _NTIPAliasClassID["crystalsword"]=29; -_NTIPAliasClassID["bsd"]=30; _NTIPAliasClassID["broadsword"]=30; -_NTIPAliasClassID["lsd"]=31; _NTIPAliasClassID["longsword"]=31; -_NTIPAliasClassID["wsd"]=32; _NTIPAliasClassID["warsword"]=32; -_NTIPAliasClassID["2hs"]=33; _NTIPAliasClassID["twohandedsword"]=33; -_NTIPAliasClassID["clm"]=34; _NTIPAliasClassID["claymore"]=34; -_NTIPAliasClassID["gis"]=35; _NTIPAliasClassID["giantsword"]=35; -_NTIPAliasClassID["bsw"]=36; _NTIPAliasClassID["bastardsword"]=36; -_NTIPAliasClassID["flb"]=37; _NTIPAliasClassID["flamberge"]=37; -_NTIPAliasClassID["gsd"]=38; _NTIPAliasClassID["greatsword"]=38; -_NTIPAliasClassID["dgr"]=39; _NTIPAliasClassID["dagger"]=39; -_NTIPAliasClassID["dir"]=40; _NTIPAliasClassID["dirk"]=40; -_NTIPAliasClassID["kri"]=41; _NTIPAliasClassID["kris"]=41; -_NTIPAliasClassID["bld"]=42; _NTIPAliasClassID["blade"]=42; -_NTIPAliasClassID["tkf"]=43; _NTIPAliasClassID["throwingknife"]=43; -_NTIPAliasClassID["tax"]=44; _NTIPAliasClassID["throwingaxe"]=44; -_NTIPAliasClassID["bkf"]=45; _NTIPAliasClassID["balancedknife"]=45; -_NTIPAliasClassID["bal"]=46; _NTIPAliasClassID["balancedaxe"]=46; -_NTIPAliasClassID["jav"]=47; _NTIPAliasClassID["javelin"]=47; -_NTIPAliasClassID["pil"]=48; _NTIPAliasClassID["pilum"]=48; -_NTIPAliasClassID["ssp"]=49; _NTIPAliasClassID["shortspear"]=49; -_NTIPAliasClassID["glv"]=50; _NTIPAliasClassID["glaive"]=50; -_NTIPAliasClassID["tsp"]=51; _NTIPAliasClassID["throwingspear"]=51; -_NTIPAliasClassID["spr"]=52; _NTIPAliasClassID["spear"]=52; -_NTIPAliasClassID["tri"]=53; _NTIPAliasClassID["trident"]=53; -_NTIPAliasClassID["brn"]=54; _NTIPAliasClassID["brandistock"]=54; -_NTIPAliasClassID["spt"]=55; _NTIPAliasClassID["spetum"]=55; -_NTIPAliasClassID["pik"]=56; _NTIPAliasClassID["pike"]=56; -_NTIPAliasClassID["bar"]=57; _NTIPAliasClassID["bardiche"]=57; -_NTIPAliasClassID["vou"]=58; _NTIPAliasClassID["voulge"]=58; -_NTIPAliasClassID["scy"]=59; _NTIPAliasClassID["scythe"]=59; -_NTIPAliasClassID["pax"]=60; _NTIPAliasClassID["poleaxe"]=60; -_NTIPAliasClassID["hal"]=61; _NTIPAliasClassID["halberd"]=61; -_NTIPAliasClassID["wsc"]=62; _NTIPAliasClassID["warscythe"]=62; -_NTIPAliasClassID["sst"]=63; _NTIPAliasClassID["shortstaff"]=63; -_NTIPAliasClassID["lst"]=64; _NTIPAliasClassID["longstaff"]=64; -_NTIPAliasClassID["cst"]=65; _NTIPAliasClassID["gnarledstaff"]=65; -_NTIPAliasClassID["bst"]=66; _NTIPAliasClassID["battlestaff"]=66; -_NTIPAliasClassID["wst"]=67; _NTIPAliasClassID["warstaff"]=67; -_NTIPAliasClassID["sbw"]=68; _NTIPAliasClassID["shortbow"]=68; -_NTIPAliasClassID["hbw"]=69; _NTIPAliasClassID["hunter'sbow"]=69; -_NTIPAliasClassID["lbw"]=70; _NTIPAliasClassID["longbow"]=70; -_NTIPAliasClassID["cbw"]=71; _NTIPAliasClassID["compositebow"]=71; -_NTIPAliasClassID["sbb"]=72; _NTIPAliasClassID["shortbattlebow"]=72; -_NTIPAliasClassID["lbb"]=73; _NTIPAliasClassID["longbattlebow"]=73; -_NTIPAliasClassID["swb"]=74; _NTIPAliasClassID["shortwarbow"]=74; -_NTIPAliasClassID["lwb"]=75; _NTIPAliasClassID["longwarbow"]=75; -_NTIPAliasClassID["lxb"]=76; _NTIPAliasClassID["lightcrossbow"]=76; -_NTIPAliasClassID["mxb"]=77; _NTIPAliasClassID["crossbow"]=77; -_NTIPAliasClassID["hxb"]=78; _NTIPAliasClassID["heavycrossbow"]=78; -_NTIPAliasClassID["rxb"]=79; _NTIPAliasClassID["repeatingcrossbow"]=79; -_NTIPAliasClassID["gps"]=80; _NTIPAliasClassID["rancidgaspotion"]=80; -_NTIPAliasClassID["ops"]=81; _NTIPAliasClassID["oilpotion"]=81; -_NTIPAliasClassID["gpm"]=82; _NTIPAliasClassID["chokinggaspotion"]=82; -_NTIPAliasClassID["opm"]=83; _NTIPAliasClassID["explodingpotion"]=83; -_NTIPAliasClassID["gpl"]=84; _NTIPAliasClassID["stranglinggaspotion"]=84; -_NTIPAliasClassID["opl"]=85; _NTIPAliasClassID["fulminatingpotion"]=85; -_NTIPAliasClassID["d33"]=86; _NTIPAliasClassID["decoygidbinn"]=86; -_NTIPAliasClassID["g33"]=87; _NTIPAliasClassID["thegidbinn"]=87; -_NTIPAliasClassID["leg"]=88; _NTIPAliasClassID["wirt'sleg"]=88; -_NTIPAliasClassID["hdm"]=89; _NTIPAliasClassID["horadricmalus"]=89; -_NTIPAliasClassID["hfh"]=90; _NTIPAliasClassID["hellforgehammer"]=90; -_NTIPAliasClassID["hst"]=91; _NTIPAliasClassID["horadricstaff"]=91; -_NTIPAliasClassID["msf"]=92; _NTIPAliasClassID["shaftofthehoradricstaff"]=92; -_NTIPAliasClassID["9ha"]=93; _NTIPAliasClassID["hatchet"]=93; -_NTIPAliasClassID["9ax"]=94; _NTIPAliasClassID["cleaver"]=94; -_NTIPAliasClassID["92a"]=95; _NTIPAliasClassID["twinaxe"]=95; -_NTIPAliasClassID["9mp"]=96; _NTIPAliasClassID["crowbill"]=96; -_NTIPAliasClassID["9wa"]=97; _NTIPAliasClassID["naga"]=97; -_NTIPAliasClassID["9la"]=98; _NTIPAliasClassID["militaryaxe"]=98; -_NTIPAliasClassID["9ba"]=99; _NTIPAliasClassID["beardedaxe"]=99; -_NTIPAliasClassID["9bt"]=100; _NTIPAliasClassID["tabar"]=100; -_NTIPAliasClassID["9ga"]=101; _NTIPAliasClassID["gothicaxe"]=101; -_NTIPAliasClassID["9gi"]=102; _NTIPAliasClassID["ancientaxe"]=102; -_NTIPAliasClassID["9wn"]=103; _NTIPAliasClassID["burntwand"]=103; -_NTIPAliasClassID["9yw"]=104; _NTIPAliasClassID["petrifiedwand"]=104; -_NTIPAliasClassID["9bw"]=105; _NTIPAliasClassID["tombwand"]=105; -_NTIPAliasClassID["9gw"]=106; _NTIPAliasClassID["gravewand"]=106; -_NTIPAliasClassID["9cl"]=107; _NTIPAliasClassID["cudgel"]=107; -_NTIPAliasClassID["9sc"]=108; _NTIPAliasClassID["runescepter"]=108; -_NTIPAliasClassID["9qs"]=109; _NTIPAliasClassID["holywatersprinkler"]=109; -_NTIPAliasClassID["9ws"]=110; _NTIPAliasClassID["divinescepter"]=110; -_NTIPAliasClassID["9sp"]=111; _NTIPAliasClassID["barbedclub"]=111; -_NTIPAliasClassID["9ma"]=112; _NTIPAliasClassID["flangedmace"]=112; -_NTIPAliasClassID["9mt"]=113; _NTIPAliasClassID["jaggedstar"]=113; -_NTIPAliasClassID["9fl"]=114; _NTIPAliasClassID["knout"]=114; -_NTIPAliasClassID["9wh"]=115; _NTIPAliasClassID["battlehammer"]=115; -_NTIPAliasClassID["9m9"]=116; _NTIPAliasClassID["warclub"]=116; -_NTIPAliasClassID["9gm"]=117; _NTIPAliasClassID["marteldefer"]=117; -_NTIPAliasClassID["9ss"]=118; _NTIPAliasClassID["gladius"]=118; -_NTIPAliasClassID["9sm"]=119; _NTIPAliasClassID["cutlass"]=119; -_NTIPAliasClassID["9sb"]=120; _NTIPAliasClassID["shamshir"]=120; -_NTIPAliasClassID["9fc"]=121; _NTIPAliasClassID["tulwar"]=121; -_NTIPAliasClassID["9cr"]=122; _NTIPAliasClassID["dimensionalblade"]=122; -_NTIPAliasClassID["9bs"]=123; _NTIPAliasClassID["battlesword"]=123; -_NTIPAliasClassID["9ls"]=124; _NTIPAliasClassID["runesword"]=124; -_NTIPAliasClassID["9wd"]=125; _NTIPAliasClassID["ancientsword"]=125; -_NTIPAliasClassID["92h"]=126; _NTIPAliasClassID["espandon"]=126; -_NTIPAliasClassID["9cm"]=127; _NTIPAliasClassID["dacianfalx"]=127; -_NTIPAliasClassID["9gs"]=128; _NTIPAliasClassID["tusksword"]=128; -_NTIPAliasClassID["9b9"]=129; _NTIPAliasClassID["gothicsword"]=129; -_NTIPAliasClassID["9fb"]=130; _NTIPAliasClassID["zweihander"]=130; -_NTIPAliasClassID["9gd"]=131; _NTIPAliasClassID["executionersword"]=131; -_NTIPAliasClassID["9dg"]=132; _NTIPAliasClassID["poignard"]=132; -_NTIPAliasClassID["9di"]=133; _NTIPAliasClassID["rondel"]=133; -_NTIPAliasClassID["9kr"]=134; _NTIPAliasClassID["cinquedeas"]=134; -_NTIPAliasClassID["9bl"]=135; _NTIPAliasClassID["stiletto"]=135; -_NTIPAliasClassID["9tk"]=136; _NTIPAliasClassID["battledart"]=136; -_NTIPAliasClassID["9ta"]=137; _NTIPAliasClassID["francisca"]=137; -_NTIPAliasClassID["9bk"]=138; _NTIPAliasClassID["wardart"]=138; -_NTIPAliasClassID["9b8"]=139; _NTIPAliasClassID["hurlbat"]=139; -_NTIPAliasClassID["9ja"]=140; _NTIPAliasClassID["warjavelin"]=140; -_NTIPAliasClassID["9pi"]=141; _NTIPAliasClassID["greatpilum"]=141; -_NTIPAliasClassID["9s9"]=142; _NTIPAliasClassID["simbilan"]=142; -_NTIPAliasClassID["9gl"]=143; _NTIPAliasClassID["spiculum"]=143; -_NTIPAliasClassID["9ts"]=144; _NTIPAliasClassID["harpoon"]=144; -_NTIPAliasClassID["9sr"]=145; _NTIPAliasClassID["warspear"]=145; -_NTIPAliasClassID["9tr"]=146; _NTIPAliasClassID["fuscina"]=146; -_NTIPAliasClassID["9br"]=147; _NTIPAliasClassID["warfork"]=147; -_NTIPAliasClassID["9st"]=148; _NTIPAliasClassID["yari"]=148; -_NTIPAliasClassID["9p9"]=149; _NTIPAliasClassID["lance"]=149; -_NTIPAliasClassID["9b7"]=150; _NTIPAliasClassID["lochaberaxe"]=150; -_NTIPAliasClassID["9vo"]=151; _NTIPAliasClassID["bill"]=151; -_NTIPAliasClassID["9s8"]=152; _NTIPAliasClassID["battlescythe"]=152; -_NTIPAliasClassID["9pa"]=153; _NTIPAliasClassID["partizan"]=153; -_NTIPAliasClassID["9h9"]=154; _NTIPAliasClassID["becdecorbin"]=154; -_NTIPAliasClassID["9wc"]=155; _NTIPAliasClassID["grimscythe"]=155; -_NTIPAliasClassID["8ss"]=156; _NTIPAliasClassID["jostaff"]=156; -_NTIPAliasClassID["8ls"]=157; _NTIPAliasClassID["quarterstaff"]=157; -_NTIPAliasClassID["8cs"]=158; _NTIPAliasClassID["cedarstaff"]=158; -_NTIPAliasClassID["8bs"]=159; _NTIPAliasClassID["gothicstaff"]=159; -_NTIPAliasClassID["8ws"]=160; _NTIPAliasClassID["runestaff"]=160; -_NTIPAliasClassID["8sb"]=161; _NTIPAliasClassID["edgebow"]=161; -_NTIPAliasClassID["8hb"]=162; _NTIPAliasClassID["razorbow"]=162; -_NTIPAliasClassID["8lb"]=163; _NTIPAliasClassID["cedarbow"]=163; -_NTIPAliasClassID["8cb"]=164; _NTIPAliasClassID["doublebow"]=164; -_NTIPAliasClassID["8s8"]=165; _NTIPAliasClassID["shortsiegebow"]=165; -_NTIPAliasClassID["8l8"]=166; _NTIPAliasClassID["largesiegebow"]=166; -_NTIPAliasClassID["8sw"]=167; _NTIPAliasClassID["runebow"]=167; -_NTIPAliasClassID["8lw"]=168; _NTIPAliasClassID["gothicbow"]=168; -_NTIPAliasClassID["8lx"]=169; _NTIPAliasClassID["arbalest"]=169; -_NTIPAliasClassID["8mx"]=170; _NTIPAliasClassID["siegecrossbow"]=170; -_NTIPAliasClassID["8hx"]=171; _NTIPAliasClassID["ballista"]=171; -_NTIPAliasClassID["8rx"]=172; _NTIPAliasClassID["chukonu"]=172; -_NTIPAliasClassID["qf1"]=173; _NTIPAliasClassID["khalim'sflail"]=173; -_NTIPAliasClassID["qf2"]=174; _NTIPAliasClassID["khalim'swill"]=174; -_NTIPAliasClassID["ktr"]=175; _NTIPAliasClassID["katar"]=175; -_NTIPAliasClassID["wrb"]=176; _NTIPAliasClassID["wristblade"]=176; -_NTIPAliasClassID["axf"]=177; _NTIPAliasClassID["hatchethands"]=177; -_NTIPAliasClassID["ces"]=178; _NTIPAliasClassID["cestus"]=178; -_NTIPAliasClassID["clw"]=179; _NTIPAliasClassID["claws"]=179; -_NTIPAliasClassID["btl"]=180; _NTIPAliasClassID["bladetalons"]=180; -_NTIPAliasClassID["skr"]=181; _NTIPAliasClassID["scissorskatar"]=181; -_NTIPAliasClassID["9ar"]=182; _NTIPAliasClassID["quhab"]=182; -_NTIPAliasClassID["9wb"]=183; _NTIPAliasClassID["wristspike"]=183; -_NTIPAliasClassID["9xf"]=184; _NTIPAliasClassID["fascia"]=184; -_NTIPAliasClassID["9cs"]=185; _NTIPAliasClassID["handscythe"]=185; -_NTIPAliasClassID["9lw"]=186; _NTIPAliasClassID["greaterclaws"]=186; -_NTIPAliasClassID["9tw"]=187; _NTIPAliasClassID["greatertalons"]=187; -_NTIPAliasClassID["9qr"]=188; _NTIPAliasClassID["scissorsquhab"]=188; -_NTIPAliasClassID["7ar"]=189; _NTIPAliasClassID["suwayyah"]=189; -_NTIPAliasClassID["7wb"]=190; _NTIPAliasClassID["wristsword"]=190; -_NTIPAliasClassID["7xf"]=191; _NTIPAliasClassID["warfist"]=191; -_NTIPAliasClassID["7cs"]=192; _NTIPAliasClassID["battlecestus"]=192; -_NTIPAliasClassID["7lw"]=193; _NTIPAliasClassID["feralclaws"]=193; -_NTIPAliasClassID["7tw"]=194; _NTIPAliasClassID["runictalons"]=194; -_NTIPAliasClassID["7qr"]=195; _NTIPAliasClassID["scissorssuwayyah"]=195; -_NTIPAliasClassID["7ha"]=196; _NTIPAliasClassID["tomahawk"]=196; -_NTIPAliasClassID["7ax"]=197; _NTIPAliasClassID["smallcrescent"]=197; -_NTIPAliasClassID["72a"]=198; _NTIPAliasClassID["ettinaxe"]=198; -_NTIPAliasClassID["7mp"]=199; _NTIPAliasClassID["warspike"]=199; -_NTIPAliasClassID["7wa"]=200; _NTIPAliasClassID["berserkeraxe"]=200; -_NTIPAliasClassID["7la"]=201; _NTIPAliasClassID["feralaxe"]=201; -_NTIPAliasClassID["7ba"]=202; _NTIPAliasClassID["silveredgedaxe"]=202; -_NTIPAliasClassID["7bt"]=203; _NTIPAliasClassID["decapitator"]=203; -_NTIPAliasClassID["7ga"]=204; _NTIPAliasClassID["championaxe"]=204; -_NTIPAliasClassID["7gi"]=205; _NTIPAliasClassID["gloriousaxe"]=205; -_NTIPAliasClassID["7wn"]=206; _NTIPAliasClassID["polishedwand"]=206; -_NTIPAliasClassID["7yw"]=207; _NTIPAliasClassID["ghostwand"]=207; -_NTIPAliasClassID["7bw"]=208; _NTIPAliasClassID["lichwand"]=208; -_NTIPAliasClassID["7gw"]=209; _NTIPAliasClassID["unearthedwand"]=209; -_NTIPAliasClassID["7cl"]=210; _NTIPAliasClassID["truncheon"]=210; -_NTIPAliasClassID["7sc"]=211; _NTIPAliasClassID["mightyscepter"]=211; -_NTIPAliasClassID["7qs"]=212; _NTIPAliasClassID["seraphrod"]=212; -_NTIPAliasClassID["7ws"]=213; _NTIPAliasClassID["caduceus"]=213; -_NTIPAliasClassID["7sp"]=214; _NTIPAliasClassID["tyrantclub"]=214; -_NTIPAliasClassID["7ma"]=215; _NTIPAliasClassID["reinforcedmace"]=215; -_NTIPAliasClassID["7mt"]=216; _NTIPAliasClassID["devilstar"]=216; -_NTIPAliasClassID["7fl"]=217; _NTIPAliasClassID["scourge"]=217; -_NTIPAliasClassID["7wh"]=218; _NTIPAliasClassID["legendarymallet"]=218; -_NTIPAliasClassID["7m7"]=219; _NTIPAliasClassID["ogremaul"]=219; -_NTIPAliasClassID["7gm"]=220; _NTIPAliasClassID["thundermaul"]=220; -_NTIPAliasClassID["7ss"]=221; _NTIPAliasClassID["falcata"]=221; -_NTIPAliasClassID["7sm"]=222; _NTIPAliasClassID["ataghan"]=222; -_NTIPAliasClassID["7sb"]=223; _NTIPAliasClassID["elegantblade"]=223; -_NTIPAliasClassID["7fc"]=224; _NTIPAliasClassID["hydraedge"]=224; -_NTIPAliasClassID["7cr"]=225; _NTIPAliasClassID["phaseblade"]=225; -_NTIPAliasClassID["7bs"]=226; _NTIPAliasClassID["conquestsword"]=226; -_NTIPAliasClassID["7ls"]=227; _NTIPAliasClassID["crypticsword"]=227; -_NTIPAliasClassID["7wd"]=228; _NTIPAliasClassID["mythicalsword"]=228; -_NTIPAliasClassID["72h"]=229; _NTIPAliasClassID["legendsword"]=229; -_NTIPAliasClassID["7cm"]=230; _NTIPAliasClassID["highlandblade"]=230; -_NTIPAliasClassID["7gs"]=231; _NTIPAliasClassID["balrogblade"]=231; -_NTIPAliasClassID["7b7"]=232; _NTIPAliasClassID["championsword"]=232; -_NTIPAliasClassID["7fb"]=233; _NTIPAliasClassID["colossussword"]=233; -_NTIPAliasClassID["7gd"]=234; _NTIPAliasClassID["colossusblade"]=234; -_NTIPAliasClassID["7dg"]=235; _NTIPAliasClassID["boneknife"]=235; -_NTIPAliasClassID["7di"]=236; _NTIPAliasClassID["mithrilpoint"]=236; -_NTIPAliasClassID["7kr"]=237; _NTIPAliasClassID["fangedknife"]=237; -_NTIPAliasClassID["7bl"]=238; _NTIPAliasClassID["legendspike"]=238; -_NTIPAliasClassID["7tk"]=239; _NTIPAliasClassID["flyingknife"]=239; -_NTIPAliasClassID["7ta"]=240; _NTIPAliasClassID["flyingaxe"]=240; -_NTIPAliasClassID["7bk"]=241; _NTIPAliasClassID["wingedknife"]=241; -_NTIPAliasClassID["7b8"]=242; _NTIPAliasClassID["wingedaxe"]=242; -_NTIPAliasClassID["7ja"]=243; _NTIPAliasClassID["hyperionjavelin"]=243; -_NTIPAliasClassID["7pi"]=244; _NTIPAliasClassID["stygianpilum"]=244; -_NTIPAliasClassID["7s7"]=245; _NTIPAliasClassID["balrogspear"]=245; -_NTIPAliasClassID["7gl"]=246; _NTIPAliasClassID["ghostglaive"]=246; -_NTIPAliasClassID["7ts"]=247; _NTIPAliasClassID["wingedharpoon"]=247; -_NTIPAliasClassID["7sr"]=248; _NTIPAliasClassID["hyperionspear"]=248; -_NTIPAliasClassID["7tr"]=249; _NTIPAliasClassID["stygianpike"]=249; -_NTIPAliasClassID["7br"]=250; _NTIPAliasClassID["mancatcher"]=250; -_NTIPAliasClassID["7st"]=251; _NTIPAliasClassID["ghostspear"]=251; -_NTIPAliasClassID["7p7"]=252; _NTIPAliasClassID["warpike"]=252; -_NTIPAliasClassID["7o7"]=253; _NTIPAliasClassID["ogreaxe"]=253; -_NTIPAliasClassID["7vo"]=254; _NTIPAliasClassID["colossusvoulge"]=254; -_NTIPAliasClassID["7s8"]=255; _NTIPAliasClassID["thresher"]=255; -_NTIPAliasClassID["7pa"]=256; _NTIPAliasClassID["crypticaxe"]=256; -_NTIPAliasClassID["7h7"]=257; _NTIPAliasClassID["greatpoleaxe"]=257; -_NTIPAliasClassID["7wc"]=258; _NTIPAliasClassID["giantthresher"]=258; -_NTIPAliasClassID["6ss"]=259; _NTIPAliasClassID["walkingstick"]=259; -_NTIPAliasClassID["6ls"]=260; _NTIPAliasClassID["stalagmite"]=260; -_NTIPAliasClassID["6cs"]=261; _NTIPAliasClassID["elderstaff"]=261; -_NTIPAliasClassID["6bs"]=262; _NTIPAliasClassID["shillelagh"]=262; -_NTIPAliasClassID["6ws"]=263; _NTIPAliasClassID["archonstaff"]=263; -_NTIPAliasClassID["6sb"]=264; _NTIPAliasClassID["spiderbow"]=264; -_NTIPAliasClassID["6hb"]=265; _NTIPAliasClassID["bladebow"]=265; -_NTIPAliasClassID["6lb"]=266; _NTIPAliasClassID["shadowbow"]=266; -_NTIPAliasClassID["6cb"]=267; _NTIPAliasClassID["greatbow"]=267; -_NTIPAliasClassID["6s7"]=268; _NTIPAliasClassID["diamondbow"]=268; -_NTIPAliasClassID["6l7"]=269; _NTIPAliasClassID["crusaderbow"]=269; -_NTIPAliasClassID["6sw"]=270; _NTIPAliasClassID["wardbow"]=270; -_NTIPAliasClassID["6lw"]=271; _NTIPAliasClassID["hydrabow"]=271; -_NTIPAliasClassID["6lx"]=272; _NTIPAliasClassID["pelletbow"]=272; -_NTIPAliasClassID["6mx"]=273; _NTIPAliasClassID["gorgoncrossbow"]=273; -_NTIPAliasClassID["6hx"]=274; _NTIPAliasClassID["colossuscrossbow"]=274; -_NTIPAliasClassID["6rx"]=275; _NTIPAliasClassID["demoncrossbow"]=275; -_NTIPAliasClassID["ob1"]=276; _NTIPAliasClassID["eagleorb"]=276; -_NTIPAliasClassID["ob2"]=277; _NTIPAliasClassID["sacredglobe"]=277; -_NTIPAliasClassID["ob3"]=278; _NTIPAliasClassID["smokedsphere"]=278; -_NTIPAliasClassID["ob4"]=279; _NTIPAliasClassID["claspedorb"]=279; -_NTIPAliasClassID["ob5"]=280; _NTIPAliasClassID["jared'sstone"]=280; -_NTIPAliasClassID["am1"]=281; _NTIPAliasClassID["stagbow"]=281; -_NTIPAliasClassID["am2"]=282; _NTIPAliasClassID["reflexbow"]=282; -_NTIPAliasClassID["am3"]=283; _NTIPAliasClassID["maidenspear"]=283; -_NTIPAliasClassID["am4"]=284; _NTIPAliasClassID["maidenpike"]=284; -_NTIPAliasClassID["am5"]=285; _NTIPAliasClassID["maidenjavelin"]=285; -_NTIPAliasClassID["ob6"]=286; _NTIPAliasClassID["glowingorb"]=286; -_NTIPAliasClassID["ob7"]=287; _NTIPAliasClassID["crystallineglobe"]=287; -_NTIPAliasClassID["ob8"]=288; _NTIPAliasClassID["cloudysphere"]=288; -_NTIPAliasClassID["ob9"]=289; _NTIPAliasClassID["sparklingball"]=289; -_NTIPAliasClassID["oba"]=290; _NTIPAliasClassID["swirlingcrystal"]=290; -_NTIPAliasClassID["am6"]=291; _NTIPAliasClassID["ashwoodbow"]=291; -_NTIPAliasClassID["am7"]=292; _NTIPAliasClassID["ceremonialbow"]=292; -_NTIPAliasClassID["am8"]=293; _NTIPAliasClassID["ceremonialspear"]=293; -_NTIPAliasClassID["am9"]=294; _NTIPAliasClassID["ceremonialpike"]=294; -_NTIPAliasClassID["ama"]=295; _NTIPAliasClassID["ceremonialjavelin"]=295; -_NTIPAliasClassID["obb"]=296; _NTIPAliasClassID["heavenlystone"]=296; -_NTIPAliasClassID["obc"]=297; _NTIPAliasClassID["eldritchorb"]=297; -_NTIPAliasClassID["obd"]=298; _NTIPAliasClassID["demonheart"]=298; -_NTIPAliasClassID["obe"]=299; _NTIPAliasClassID["vortexorb"]=299; -_NTIPAliasClassID["obf"]=300; _NTIPAliasClassID["dimensionalshard"]=300; -_NTIPAliasClassID["amb"]=301; _NTIPAliasClassID["matriarchalbow"]=301; -_NTIPAliasClassID["amc"]=302; _NTIPAliasClassID["grandmatronbow"]=302; -_NTIPAliasClassID["amd"]=303; _NTIPAliasClassID["matriarchalspear"]=303; -_NTIPAliasClassID["ame"]=304; _NTIPAliasClassID["matriarchalpike"]=304; -_NTIPAliasClassID["amf"]=305; _NTIPAliasClassID["matriarchaljavelin"]=305; -_NTIPAliasClassID["cap"]=306; -_NTIPAliasClassID["skp"]=307; _NTIPAliasClassID["skullcap"]=307; -_NTIPAliasClassID["hlm"]=308; _NTIPAliasClassID["helm"]=308; -_NTIPAliasClassID["fhl"]=309; _NTIPAliasClassID["fullhelm"]=309; -_NTIPAliasClassID["ghm"]=310; _NTIPAliasClassID["greathelm"]=310; -_NTIPAliasClassID["crn"]=311; _NTIPAliasClassID["crown"]=311; -_NTIPAliasClassID["msk"]=312; _NTIPAliasClassID["mask"]=312; -_NTIPAliasClassID["qui"]=313; _NTIPAliasClassID["quiltedarmor"]=313; -_NTIPAliasClassID["lea"]=314; _NTIPAliasClassID["leatherarmor"]=314; -_NTIPAliasClassID["hla"]=315; _NTIPAliasClassID["hardleatherarmor"]=315; -_NTIPAliasClassID["stu"]=316; _NTIPAliasClassID["studdedleather"]=316; -_NTIPAliasClassID["rng"]=317; _NTIPAliasClassID["ringmail"]=317; -_NTIPAliasClassID["scl"]=318; _NTIPAliasClassID["scalemail"]=318; -_NTIPAliasClassID["chn"]=319; _NTIPAliasClassID["chainmail"]=319; -_NTIPAliasClassID["brs"]=320; _NTIPAliasClassID["breastplate"]=320; -_NTIPAliasClassID["spl"]=321; _NTIPAliasClassID["splintmail"]=321; -_NTIPAliasClassID["plt"]=322; _NTIPAliasClassID["platemail"]=322; -_NTIPAliasClassID["fld"]=323; _NTIPAliasClassID["fieldplate"]=323; -_NTIPAliasClassID["gth"]=324; _NTIPAliasClassID["gothicplate"]=324; -_NTIPAliasClassID["ful"]=325; _NTIPAliasClassID["fullplatemail"]=325; -_NTIPAliasClassID["aar"]=326; _NTIPAliasClassID["ancientarmor"]=326; -_NTIPAliasClassID["ltp"]=327; _NTIPAliasClassID["lightplate"]=327; -_NTIPAliasClassID["buc"]=328; _NTIPAliasClassID["buckler"]=328; -_NTIPAliasClassID["sml"]=329; _NTIPAliasClassID["smallshield"]=329; -_NTIPAliasClassID["lrg"]=330; _NTIPAliasClassID["largeshield"]=330; -_NTIPAliasClassID["kit"]=331; _NTIPAliasClassID["kiteshield"]=331; -_NTIPAliasClassID["tow"]=332; _NTIPAliasClassID["towershield"]=332; -_NTIPAliasClassID["gts"]=333; _NTIPAliasClassID["gothicshield"]=333; -_NTIPAliasClassID["lgl"]=334; _NTIPAliasClassID["leathergloves"]=334; -_NTIPAliasClassID["vgl"]=335; _NTIPAliasClassID["heavygloves"]=335; -_NTIPAliasClassID["mgl"]=336; _NTIPAliasClassID["chaingloves"]=336; -_NTIPAliasClassID["tgl"]=337; _NTIPAliasClassID["lightgauntlets"]=337; -_NTIPAliasClassID["hgl"]=338; _NTIPAliasClassID["gauntlets"]=338; -_NTIPAliasClassID["lbt"]=339; _NTIPAliasClassID["boots"]=339; -_NTIPAliasClassID["vbt"]=340; _NTIPAliasClassID["heavyboots"]=340; -_NTIPAliasClassID["mbt"]=341; _NTIPAliasClassID["chainboots"]=341; -_NTIPAliasClassID["tbt"]=342; _NTIPAliasClassID["lightplatedboots"]=342; -_NTIPAliasClassID["hbt"]=343; _NTIPAliasClassID["greaves"]=343; -_NTIPAliasClassID["lbl"]=344; _NTIPAliasClassID["sash"]=344; -_NTIPAliasClassID["vbl"]=345; _NTIPAliasClassID["lightbelt"]=345; -_NTIPAliasClassID["mbl"]=346; _NTIPAliasClassID["belt"]=346; -_NTIPAliasClassID["tbl"]=347; _NTIPAliasClassID["heavybelt"]=347; -_NTIPAliasClassID["hbl"]=348; _NTIPAliasClassID["platedbelt"]=348; -_NTIPAliasClassID["bhm"]=349; _NTIPAliasClassID["bonehelm"]=349; -_NTIPAliasClassID["bsh"]=350; _NTIPAliasClassID["boneshield"]=350; -_NTIPAliasClassID["spk"]=351; _NTIPAliasClassID["spikedshield"]=351; -_NTIPAliasClassID["xap"]=352; _NTIPAliasClassID["warhat"]=352; -_NTIPAliasClassID["xkp"]=353; _NTIPAliasClassID["sallet"]=353; -_NTIPAliasClassID["xlm"]=354; _NTIPAliasClassID["casque"]=354; -_NTIPAliasClassID["xhl"]=355; _NTIPAliasClassID["basinet"]=355; -_NTIPAliasClassID["xhm"]=356; _NTIPAliasClassID["wingedhelm"]=356; -_NTIPAliasClassID["xrn"]=357; _NTIPAliasClassID["grandcrown"]=357; -_NTIPAliasClassID["xsk"]=358; _NTIPAliasClassID["deathmask"]=358; -_NTIPAliasClassID["xui"]=359; _NTIPAliasClassID["ghostarmor"]=359; -_NTIPAliasClassID["xea"]=360; _NTIPAliasClassID["serpentskinarmor"]=360; -_NTIPAliasClassID["xla"]=361; _NTIPAliasClassID["demonhidearmor"]=361; -_NTIPAliasClassID["xtu"]=362; _NTIPAliasClassID["trellisedarmor"]=362; -_NTIPAliasClassID["xng"]=363; _NTIPAliasClassID["linkedmail"]=363; -_NTIPAliasClassID["xcl"]=364; _NTIPAliasClassID["tigulatedmail"]=364; -_NTIPAliasClassID["xhn"]=365; _NTIPAliasClassID["mesharmor"]=365; -_NTIPAliasClassID["xrs"]=366; _NTIPAliasClassID["cuirass"]=366; -_NTIPAliasClassID["xpl"]=367; _NTIPAliasClassID["russetarmor"]=367; -_NTIPAliasClassID["xlt"]=368; _NTIPAliasClassID["templarcoat"]=368; -_NTIPAliasClassID["xld"]=369; _NTIPAliasClassID["sharktootharmor"]=369; -_NTIPAliasClassID["xth"]=370; _NTIPAliasClassID["embossedplate"]=370; -_NTIPAliasClassID["xul"]=371; _NTIPAliasClassID["chaosarmor"]=371; -_NTIPAliasClassID["xar"]=372; _NTIPAliasClassID["ornateplate"]=372; -_NTIPAliasClassID["xtp"]=373; _NTIPAliasClassID["mageplate"]=373; -_NTIPAliasClassID["xuc"]=374; _NTIPAliasClassID["defender"]=374; -_NTIPAliasClassID["xml"]=375; _NTIPAliasClassID["roundshield"]=375; -_NTIPAliasClassID["xrg"]=376; _NTIPAliasClassID["scutum"]=376; -_NTIPAliasClassID["xit"]=377; _NTIPAliasClassID["dragonshield"]=377; -_NTIPAliasClassID["xow"]=378; _NTIPAliasClassID["pavise"]=378; -_NTIPAliasClassID["xts"]=379; _NTIPAliasClassID["ancientshield"]=379; -_NTIPAliasClassID["xlg"]=380; _NTIPAliasClassID["demonhidegloves"]=380; -_NTIPAliasClassID["xvg"]=381; _NTIPAliasClassID["sharkskingloves"]=381; -_NTIPAliasClassID["xmg"]=382; _NTIPAliasClassID["heavybracers"]=382; -_NTIPAliasClassID["xtg"]=383; _NTIPAliasClassID["battlegauntlets"]=383; -_NTIPAliasClassID["xhg"]=384; _NTIPAliasClassID["wargauntlets"]=384; -_NTIPAliasClassID["xlb"]=385; _NTIPAliasClassID["demonhideboots"]=385; -_NTIPAliasClassID["xvb"]=386; _NTIPAliasClassID["sharkskinboots"]=386; -_NTIPAliasClassID["xmb"]=387; _NTIPAliasClassID["meshboots"]=387; -_NTIPAliasClassID["xtb"]=388; _NTIPAliasClassID["battleboots"]=388; -_NTIPAliasClassID["xhb"]=389; _NTIPAliasClassID["warboots"]=389; -_NTIPAliasClassID["zlb"]=390; _NTIPAliasClassID["demonhidesash"]=390; -_NTIPAliasClassID["zvb"]=391; _NTIPAliasClassID["sharkskinbelt"]=391; -_NTIPAliasClassID["zmb"]=392; _NTIPAliasClassID["meshbelt"]=392; -_NTIPAliasClassID["ztb"]=393; _NTIPAliasClassID["battlebelt"]=393; -_NTIPAliasClassID["zhb"]=394; _NTIPAliasClassID["warbelt"]=394; -_NTIPAliasClassID["xh9"]=395; _NTIPAliasClassID["grimhelm"]=395; -_NTIPAliasClassID["xsh"]=396; _NTIPAliasClassID["grimshield"]=396; -_NTIPAliasClassID["xpk"]=397; _NTIPAliasClassID["barbedshield"]=397; -_NTIPAliasClassID["dr1"]=398; _NTIPAliasClassID["wolfhead"]=398; -_NTIPAliasClassID["dr2"]=399; _NTIPAliasClassID["hawkhelm"]=399; -_NTIPAliasClassID["dr3"]=400; _NTIPAliasClassID["antlers"]=400; -_NTIPAliasClassID["dr4"]=401; _NTIPAliasClassID["falconmask"]=401; -_NTIPAliasClassID["dr5"]=402; _NTIPAliasClassID["spiritmask"]=402; -_NTIPAliasClassID["ba1"]=403; _NTIPAliasClassID["jawbonecap"]=403; -_NTIPAliasClassID["ba2"]=404; _NTIPAliasClassID["fangedhelm"]=404; -_NTIPAliasClassID["ba3"]=405; _NTIPAliasClassID["hornedhelm"]=405; -_NTIPAliasClassID["ba4"]=406; _NTIPAliasClassID["assaulthelmet"]=406; -_NTIPAliasClassID["ba5"]=407; _NTIPAliasClassID["avengerguard"]=407; -_NTIPAliasClassID["pa1"]=408; _NTIPAliasClassID["targe"]=408; -_NTIPAliasClassID["pa2"]=409; _NTIPAliasClassID["rondache"]=409; -_NTIPAliasClassID["pa3"]=410; _NTIPAliasClassID["heraldicshield"]=410; -_NTIPAliasClassID["pa4"]=411; _NTIPAliasClassID["aerinshield"]=411; -_NTIPAliasClassID["pa5"]=412; _NTIPAliasClassID["crownshield"]=412; -_NTIPAliasClassID["ne1"]=413; _NTIPAliasClassID["preservedhead"]=413; -_NTIPAliasClassID["ne2"]=414; _NTIPAliasClassID["zombiehead"]=414; -_NTIPAliasClassID["ne3"]=415; _NTIPAliasClassID["unravellerhead"]=415; -_NTIPAliasClassID["ne4"]=416; _NTIPAliasClassID["gargoylehead"]=416; -_NTIPAliasClassID["ne5"]=417; _NTIPAliasClassID["demonhead"]=417; -_NTIPAliasClassID["ci0"]=418; _NTIPAliasClassID["circlet"]=418; -_NTIPAliasClassID["ci1"]=419; _NTIPAliasClassID["coronet"]=419; -_NTIPAliasClassID["ci2"]=420; _NTIPAliasClassID["tiara"]=420; -_NTIPAliasClassID["ci3"]=421; _NTIPAliasClassID["diadem"]=421; -_NTIPAliasClassID["uap"]=422; _NTIPAliasClassID["shako"]=422; -_NTIPAliasClassID["ukp"]=423; _NTIPAliasClassID["hydraskull"]=423; -_NTIPAliasClassID["ulm"]=424; _NTIPAliasClassID["armet"]=424; -_NTIPAliasClassID["uhl"]=425; _NTIPAliasClassID["giantconch"]=425; -_NTIPAliasClassID["uhm"]=426; _NTIPAliasClassID["spiredhelm"]=426; -_NTIPAliasClassID["urn"]=427; _NTIPAliasClassID["corona"]=427; -_NTIPAliasClassID["usk"]=428; _NTIPAliasClassID["demonhead"]=428; -_NTIPAliasClassID["uui"]=429; _NTIPAliasClassID["duskshroud"]=429; -_NTIPAliasClassID["uea"]=430; _NTIPAliasClassID["wyrmhide"]=430; -_NTIPAliasClassID["ula"]=431; _NTIPAliasClassID["scarabhusk"]=431; -_NTIPAliasClassID["utu"]=432; _NTIPAliasClassID["wirefleece"]=432; -_NTIPAliasClassID["ung"]=433; _NTIPAliasClassID["diamondmail"]=433; -_NTIPAliasClassID["ucl"]=434; _NTIPAliasClassID["loricatedmail"]=434; -_NTIPAliasClassID["uhn"]=435; _NTIPAliasClassID["boneweave"]=435; -_NTIPAliasClassID["urs"]=436; _NTIPAliasClassID["greathauberk"]=436; -_NTIPAliasClassID["upl"]=437; _NTIPAliasClassID["balrogskin"]=437; -_NTIPAliasClassID["ult"]=438; _NTIPAliasClassID["hellforgeplate"]=438; -_NTIPAliasClassID["uld"]=439; _NTIPAliasClassID["krakenshell"]=439; -_NTIPAliasClassID["uth"]=440; _NTIPAliasClassID["lacqueredplate"]=440; -_NTIPAliasClassID["uul"]=441; _NTIPAliasClassID["shadowplate"]=441; -_NTIPAliasClassID["uar"]=442; _NTIPAliasClassID["sacredarmor"]=442; -_NTIPAliasClassID["utp"]=443; _NTIPAliasClassID["archonplate"]=443; -_NTIPAliasClassID["uuc"]=444; _NTIPAliasClassID["heater"]=444; -_NTIPAliasClassID["uml"]=445; _NTIPAliasClassID["luna"]=445; -_NTIPAliasClassID["urg"]=446; _NTIPAliasClassID["hyperion"]=446; -_NTIPAliasClassID["uit"]=447; _NTIPAliasClassID["monarch"]=447; -_NTIPAliasClassID["uow"]=448; _NTIPAliasClassID["aegis"]=448; -_NTIPAliasClassID["uts"]=449; _NTIPAliasClassID["ward"]=449; -_NTIPAliasClassID["ulg"]=450; _NTIPAliasClassID["bramblemitts"]=450; -_NTIPAliasClassID["uvg"]=451; _NTIPAliasClassID["vampirebonegloves"]=451; -_NTIPAliasClassID["umg"]=452; _NTIPAliasClassID["vambraces"]=452; -_NTIPAliasClassID["utg"]=453; _NTIPAliasClassID["crusadergauntlets"]=453; -_NTIPAliasClassID["uhg"]=454; _NTIPAliasClassID["ogregauntlets"]=454; -_NTIPAliasClassID["ulb"]=455; _NTIPAliasClassID["wyrmhideboots"]=455; -_NTIPAliasClassID["uvb"]=456; _NTIPAliasClassID["scarabshellboots"]=456; -_NTIPAliasClassID["umb"]=457; _NTIPAliasClassID["boneweaveboots"]=457; -_NTIPAliasClassID["utb"]=458; _NTIPAliasClassID["mirroredboots"]=458; -_NTIPAliasClassID["uhb"]=459; _NTIPAliasClassID["myrmidongreaves"]=459; -_NTIPAliasClassID["ulc"]=460; _NTIPAliasClassID["spiderwebsash"]=460; -_NTIPAliasClassID["uvc"]=461; _NTIPAliasClassID["vampirefangbelt"]=461; -_NTIPAliasClassID["umc"]=462; _NTIPAliasClassID["mithrilcoil"]=462; -_NTIPAliasClassID["utc"]=463; _NTIPAliasClassID["trollbelt"]=463; -_NTIPAliasClassID["uhc"]=464; _NTIPAliasClassID["colossusgirdle"]=464; -_NTIPAliasClassID["uh9"]=465; _NTIPAliasClassID["bonevisage"]=465; -_NTIPAliasClassID["ush"]=466; _NTIPAliasClassID["trollnest"]=466; -_NTIPAliasClassID["upk"]=467; _NTIPAliasClassID["bladebarrier"]=467; -_NTIPAliasClassID["dr6"]=468; _NTIPAliasClassID["alphahelm"]=468; -_NTIPAliasClassID["dr7"]=469; _NTIPAliasClassID["griffonheaddress"]=469; -_NTIPAliasClassID["dr8"]=470; _NTIPAliasClassID["hunter'sguise"]=470; -_NTIPAliasClassID["dr9"]=471; _NTIPAliasClassID["sacredfeathers"]=471; -_NTIPAliasClassID["dra"]=472; _NTIPAliasClassID["totemicmask"]=472; -_NTIPAliasClassID["ba6"]=473; _NTIPAliasClassID["jawbonevisor"]=473; -_NTIPAliasClassID["ba7"]=474; _NTIPAliasClassID["lionhelm"]=474; -_NTIPAliasClassID["ba8"]=475; _NTIPAliasClassID["ragemask"]=475; -_NTIPAliasClassID["ba9"]=476; _NTIPAliasClassID["savagehelmet"]=476; -_NTIPAliasClassID["baa"]=477; _NTIPAliasClassID["slayerguard"]=477; -_NTIPAliasClassID["pa6"]=478; _NTIPAliasClassID["akarantarge"]=478; -_NTIPAliasClassID["pa7"]=479; _NTIPAliasClassID["akaranrondache"]=479; -_NTIPAliasClassID["pa8"]=480; _NTIPAliasClassID["protectorshield"]=480; -_NTIPAliasClassID["pa9"]=481; _NTIPAliasClassID["gildedshield"]=481; -_NTIPAliasClassID["paa"]=482; _NTIPAliasClassID["royalshield"]=482; -_NTIPAliasClassID["ne6"]=483; _NTIPAliasClassID["mummifiedtrophy"]=483; -_NTIPAliasClassID["ne7"]=484; _NTIPAliasClassID["fetishtrophy"]=484; -_NTIPAliasClassID["ne8"]=485; _NTIPAliasClassID["sextontrophy"]=485; -_NTIPAliasClassID["ne9"]=486; _NTIPAliasClassID["cantortrophy"]=486; -_NTIPAliasClassID["nea"]=487; _NTIPAliasClassID["hierophanttrophy"]=487; -_NTIPAliasClassID["drb"]=488; _NTIPAliasClassID["bloodspirit"]=488; -_NTIPAliasClassID["drc"]=489; _NTIPAliasClassID["sunspirit"]=489; -_NTIPAliasClassID["drd"]=490; _NTIPAliasClassID["earthspirit"]=490; -_NTIPAliasClassID["dre"]=491; _NTIPAliasClassID["skyspirit"]=491; -_NTIPAliasClassID["drf"]=492; _NTIPAliasClassID["dreamspirit"]=492; -_NTIPAliasClassID["bab"]=493; _NTIPAliasClassID["carnagehelm"]=493; -_NTIPAliasClassID["bac"]=494; _NTIPAliasClassID["furyvisor"]=494; -_NTIPAliasClassID["bad"]=495; _NTIPAliasClassID["destroyerhelm"]=495; -_NTIPAliasClassID["bae"]=496; _NTIPAliasClassID["conquerorcrown"]=496; -_NTIPAliasClassID["baf"]=497; _NTIPAliasClassID["guardiancrown"]=497; -_NTIPAliasClassID["pab"]=498; _NTIPAliasClassID["sacredtarge"]=498; -_NTIPAliasClassID["pac"]=499; _NTIPAliasClassID["sacredrondache"]=499; -_NTIPAliasClassID["pad"]=500; _NTIPAliasClassID["kurastshield"]=500; -_NTIPAliasClassID["pae"]=501; _NTIPAliasClassID["zakarumshield"]=501; -_NTIPAliasClassID["paf"]=502; _NTIPAliasClassID["vortexshield"]=502; -_NTIPAliasClassID["neb"]=503; _NTIPAliasClassID["minionskull"]=503; -_NTIPAliasClassID["neg"]=504; _NTIPAliasClassID["hellspawnskull"]=504; -_NTIPAliasClassID["ned"]=505; _NTIPAliasClassID["overseerskull"]=505; -_NTIPAliasClassID["nee"]=506; _NTIPAliasClassID["succubusskull"]=506; -_NTIPAliasClassID["nef"]=507; _NTIPAliasClassID["bloodlordskull"]=507; -_NTIPAliasClassID["elx"]=508; _NTIPAliasClassID["elixir"]=508; -_NTIPAliasClassID["hpo"]=509; -_NTIPAliasClassID["mpo"]=510; -_NTIPAliasClassID["hpf"]=511; -_NTIPAliasClassID["mpf"]=512; -_NTIPAliasClassID["vps"]=513; _NTIPAliasClassID["staminapotion"]=513; -_NTIPAliasClassID["yps"]=514; _NTIPAliasClassID["antidotepotion"]=514; -_NTIPAliasClassID["rvs"]=515; _NTIPAliasClassID["rejuvenationpotion"]=515; -_NTIPAliasClassID["rvl"]=516; _NTIPAliasClassID["fullrejuvenationpotion"]=516; -_NTIPAliasClassID["wms"]=517; _NTIPAliasClassID["thawingpotion"]=517; -_NTIPAliasClassID["tbk"]=518; _NTIPAliasClassID["tomeoftownportal"]=518; -_NTIPAliasClassID["ibk"]=519; _NTIPAliasClassID["tomeofidentify"]=519; -_NTIPAliasClassID["amu"]=520; _NTIPAliasClassID["amulet"]=520; -_NTIPAliasClassID["vip"]=521; _NTIPAliasClassID["topofthehoradricstaff"]=521; -_NTIPAliasClassID["rin"]=522; _NTIPAliasClassID["ring"]=522; -_NTIPAliasClassID["gld"]=523; _NTIPAliasClassID["gold"]=523; -_NTIPAliasClassID["bks"]=524; _NTIPAliasClassID["scrollofinifuss"]=524; -_NTIPAliasClassID["bkd"]=525; _NTIPAliasClassID["keytothecairnstones"]=525; -_NTIPAliasClassID["aqv"]=526; _NTIPAliasClassID["arrows"]=526; -_NTIPAliasClassID["tch"]=527; _NTIPAliasClassID["torch"]=527; -_NTIPAliasClassID["cqv"]=528; _NTIPAliasClassID["bolts"]=528; -_NTIPAliasClassID["tsc"]=529; _NTIPAliasClassID["scrolloftownportal"]=529; -_NTIPAliasClassID["isc"]=530; _NTIPAliasClassID["scrollofidentify"]=530; -_NTIPAliasClassID["hrt"]=531; _NTIPAliasClassID["heart"]=531; -_NTIPAliasClassID["brz"]=532; _NTIPAliasClassID["brain"]=532; -_NTIPAliasClassID["jaw"]=533; _NTIPAliasClassID["jawbone"]=533; -_NTIPAliasClassID["eyz"]=534; _NTIPAliasClassID["eye"]=534; -_NTIPAliasClassID["hrn"]=535; _NTIPAliasClassID["horn"]=535; -_NTIPAliasClassID["tal"]=536; _NTIPAliasClassID["tail"]=536; -_NTIPAliasClassID["flg"]=537; _NTIPAliasClassID["flag"]=537; -_NTIPAliasClassID["fng"]=538; _NTIPAliasClassID["fang"]=538; -_NTIPAliasClassID["qll"]=539; _NTIPAliasClassID["quill"]=539; -_NTIPAliasClassID["sol"]=540; _NTIPAliasClassID["soul"]=540; -_NTIPAliasClassID["scz"]=541; _NTIPAliasClassID["scalp"]=541; -_NTIPAliasClassID["spe"]=542; _NTIPAliasClassID["spleen"]=542; -_NTIPAliasClassID["key"]=543; -_NTIPAliasClassID["luv"]=544; _NTIPAliasClassID["theblacktowerkey"]=544; -_NTIPAliasClassID["xyz"]=545; _NTIPAliasClassID["potionoflife"]=545; -_NTIPAliasClassID["j34"]=546; _NTIPAliasClassID["ajadefigurine"]=546; -_NTIPAliasClassID["g34"]=547; _NTIPAliasClassID["thegoldenbird"]=547; -_NTIPAliasClassID["bbb"]=548; _NTIPAliasClassID["lamesen'stome"]=548; -_NTIPAliasClassID["box"]=549; _NTIPAliasClassID["horadriccube"]=549; -_NTIPAliasClassID["tr1"]=550; _NTIPAliasClassID["horadricscroll"]=550; -_NTIPAliasClassID["mss"]=551; _NTIPAliasClassID["mephisto'ssoulstone"]=551; -_NTIPAliasClassID["ass"]=552; _NTIPAliasClassID["bookofskill"]=552; -_NTIPAliasClassID["qey"]=553; _NTIPAliasClassID["khalim'seye"]=553; -_NTIPAliasClassID["qhr"]=554; _NTIPAliasClassID["khalim'sheart"]=554; -_NTIPAliasClassID["qbr"]=555; _NTIPAliasClassID["khalim'sbrain"]=555; -_NTIPAliasClassID["ear"]=556; -_NTIPAliasClassID["gcv"]=557; _NTIPAliasClassID["chippedamethyst"]=557; -_NTIPAliasClassID["gfv"]=558; _NTIPAliasClassID["flawedamethyst"]=558; -_NTIPAliasClassID["gsv"]=559; _NTIPAliasClassID["amethyst"]=559; -_NTIPAliasClassID["gzv"]=560; _NTIPAliasClassID["flawlessamethyst"]=560; -_NTIPAliasClassID["gpv"]=561; _NTIPAliasClassID["perfectamethyst"]=561; -_NTIPAliasClassID["gcy"]=562; _NTIPAliasClassID["chippedtopaz"]=562; -_NTIPAliasClassID["gfy"]=563; _NTIPAliasClassID["flawedtopaz"]=563; -_NTIPAliasClassID["gsy"]=564; _NTIPAliasClassID["topaz"]=564; -_NTIPAliasClassID["gly"]=565; _NTIPAliasClassID["flawlesstopaz"]=565; -_NTIPAliasClassID["gpy"]=566; _NTIPAliasClassID["perfecttopaz"]=566; -_NTIPAliasClassID["gcb"]=567; _NTIPAliasClassID["chippedsapphire"]=567; -_NTIPAliasClassID["gfb"]=568; _NTIPAliasClassID["flawedsapphire"]=568; -_NTIPAliasClassID["gsb"]=569; _NTIPAliasClassID["sapphire"]=569; -_NTIPAliasClassID["glb"]=570; _NTIPAliasClassID["flawlesssapphire"]=570; -_NTIPAliasClassID["gpb"]=571; _NTIPAliasClassID["perfectsapphire"]=571; -_NTIPAliasClassID["gcg"]=572; _NTIPAliasClassID["chippedemerald"]=572; -_NTIPAliasClassID["gfg"]=573; _NTIPAliasClassID["flawedemerald"]=573; -_NTIPAliasClassID["gsg"]=574; _NTIPAliasClassID["emerald"]=574; -_NTIPAliasClassID["glg"]=575; _NTIPAliasClassID["flawlessemerald"]=575; -_NTIPAliasClassID["gpg"]=576; _NTIPAliasClassID["perfectemerald"]=576; -_NTIPAliasClassID["gcr"]=577; _NTIPAliasClassID["chippedruby"]=577; -_NTIPAliasClassID["gfr"]=578; _NTIPAliasClassID["flawedruby"]=578; -_NTIPAliasClassID["gsr"]=579; _NTIPAliasClassID["ruby"]=579; -_NTIPAliasClassID["glr"]=580; _NTIPAliasClassID["flawlessruby"]=580; -_NTIPAliasClassID["gpr"]=581; _NTIPAliasClassID["perfectruby"]=581; -_NTIPAliasClassID["gcw"]=582; _NTIPAliasClassID["chippeddiamond"]=582; -_NTIPAliasClassID["gfw"]=583; _NTIPAliasClassID["flaweddiamond"]=583; -_NTIPAliasClassID["gsw"]=584; _NTIPAliasClassID["diamond"]=584; -_NTIPAliasClassID["glw"]=585; _NTIPAliasClassID["flawlessdiamond"]=585; -_NTIPAliasClassID["gpw"]=586; _NTIPAliasClassID["perfectdiamond"]=586; -_NTIPAliasClassID["hp1"]=587; _NTIPAliasClassID["minorhealingpotion"]=587; -_NTIPAliasClassID["hp2"]=588; _NTIPAliasClassID["lighthealingpotion"]=588; -_NTIPAliasClassID["hp3"]=589; _NTIPAliasClassID["healingpotion"]=589; -_NTIPAliasClassID["hp4"]=590; _NTIPAliasClassID["greaterhealingpotion"]=590; -_NTIPAliasClassID["hp5"]=591; _NTIPAliasClassID["superhealingpotion"]=591; -_NTIPAliasClassID["mp1"]=592; _NTIPAliasClassID["minormanapotion"]=592; -_NTIPAliasClassID["mp2"]=593; _NTIPAliasClassID["lightmanapotion"]=593; -_NTIPAliasClassID["mp3"]=594; _NTIPAliasClassID["manapotion"]=594; -_NTIPAliasClassID["mp4"]=595; _NTIPAliasClassID["greatermanapotion"]=595; -_NTIPAliasClassID["mp5"]=596; _NTIPAliasClassID["supermanapotion"]=596; -_NTIPAliasClassID["skc"]=597; _NTIPAliasClassID["chippedskull"]=597; -_NTIPAliasClassID["skf"]=598; _NTIPAliasClassID["flawedskull"]=598; -_NTIPAliasClassID["sku"]=599; _NTIPAliasClassID["skull"]=599; -_NTIPAliasClassID["skl"]=600; _NTIPAliasClassID["flawlessskull"]=600; -_NTIPAliasClassID["skz"]=601; _NTIPAliasClassID["perfectskull"]=601; -_NTIPAliasClassID["hrb"]=602; _NTIPAliasClassID["herb"]=602; -_NTIPAliasClassID["cm1"]=603; _NTIPAliasClassID["smallcharm"]=603; -_NTIPAliasClassID["cm2"]=604; _NTIPAliasClassID["largecharm"]=604; -_NTIPAliasClassID["cm3"]=605; _NTIPAliasClassID["grandcharm"]=605; -_NTIPAliasClassID["rps"]=606; -_NTIPAliasClassID["rpl"]=607; -_NTIPAliasClassID["bps"]=608; -_NTIPAliasClassID["bpl"]=609; -_NTIPAliasClassID["r01"]=610; _NTIPAliasClassID["elrune"]=610; -_NTIPAliasClassID["r02"]=611; _NTIPAliasClassID["eldrune"]=611; -_NTIPAliasClassID["r03"]=612; _NTIPAliasClassID["tirrune"]=612; -_NTIPAliasClassID["r04"]=613; _NTIPAliasClassID["nefrune"]=613; -_NTIPAliasClassID["r05"]=614; _NTIPAliasClassID["ethrune"]=614; -_NTIPAliasClassID["r06"]=615; _NTIPAliasClassID["ithrune"]=615; -_NTIPAliasClassID["r07"]=616; _NTIPAliasClassID["talrune"]=616; -_NTIPAliasClassID["r08"]=617; _NTIPAliasClassID["ralrune"]=617; -_NTIPAliasClassID["r09"]=618; _NTIPAliasClassID["ortrune"]=618; -_NTIPAliasClassID["r10"]=619; _NTIPAliasClassID["thulrune"]=619; -_NTIPAliasClassID["r11"]=620; _NTIPAliasClassID["amnrune"]=620; -_NTIPAliasClassID["r12"]=621; _NTIPAliasClassID["solrune"]=621; -_NTIPAliasClassID["r13"]=622; _NTIPAliasClassID["shaelrune"]=622; -_NTIPAliasClassID["r14"]=623; _NTIPAliasClassID["dolrune"]=623; -_NTIPAliasClassID["r15"]=624; _NTIPAliasClassID["helrune"]=624; -_NTIPAliasClassID["r16"]=625; _NTIPAliasClassID["iorune"]=625; -_NTIPAliasClassID["r17"]=626; _NTIPAliasClassID["lumrune"]=626; -_NTIPAliasClassID["r18"]=627; _NTIPAliasClassID["korune"]=627; -_NTIPAliasClassID["r19"]=628; _NTIPAliasClassID["falrune"]=628; -_NTIPAliasClassID["r20"]=629; _NTIPAliasClassID["lemrune"]=629; -_NTIPAliasClassID["r21"]=630; _NTIPAliasClassID["pulrune"]=630; -_NTIPAliasClassID["r22"]=631; _NTIPAliasClassID["umrune"]=631; -_NTIPAliasClassID["r23"]=632; _NTIPAliasClassID["malrune"]=632; -_NTIPAliasClassID["r24"]=633; _NTIPAliasClassID["istrune"]=633; -_NTIPAliasClassID["r25"]=634; _NTIPAliasClassID["gulrune"]=634; -_NTIPAliasClassID["r26"]=635; _NTIPAliasClassID["vexrune"]=635; -_NTIPAliasClassID["r27"]=636; _NTIPAliasClassID["ohmrune"]=636; -_NTIPAliasClassID["r28"]=637; _NTIPAliasClassID["lorune"]=637; -_NTIPAliasClassID["r29"]=638; _NTIPAliasClassID["surrune"]=638; -_NTIPAliasClassID["r30"]=639; _NTIPAliasClassID["berrune"]=639; -_NTIPAliasClassID["r31"]=640; _NTIPAliasClassID["jahrune"]=640; -_NTIPAliasClassID["r32"]=641; _NTIPAliasClassID["chamrune"]=641; -_NTIPAliasClassID["r33"]=642; _NTIPAliasClassID["zodrune"]=642; -_NTIPAliasClassID["jew"]=643; _NTIPAliasClassID["jewel"]=643; -_NTIPAliasClassID["ice"]=644; _NTIPAliasClassID["malah'spotion"]=644; -_NTIPAliasClassID["0sc"]=645; _NTIPAliasClassID["scrollofknowledge"]=645; -_NTIPAliasClassID["tr2"]=646; _NTIPAliasClassID["scrollofresistance"]=646; -_NTIPAliasClassID["pk1"]=647; _NTIPAliasClassID["keyofterror"]=647; -_NTIPAliasClassID["pk2"]=648; _NTIPAliasClassID["keyofhate"]=648; -_NTIPAliasClassID["pk3"]=649; _NTIPAliasClassID["keyofdestruction"]=649; -_NTIPAliasClassID["dhn"]=650; _NTIPAliasClassID["diablo'shorn"]=650; -_NTIPAliasClassID["bey"]=651; _NTIPAliasClassID["baal'seye"]=651; -_NTIPAliasClassID["mbr"]=652; _NTIPAliasClassID["mephisto'sbrain"]=652; -_NTIPAliasClassID["toa"]=653; _NTIPAliasClassID["tokenofabsolution"]=653; -_NTIPAliasClassID["tes"]=654; _NTIPAliasClassID["twistedessenceofsuffering"]=654; -_NTIPAliasClassID["ceh"]=655; _NTIPAliasClassID["chargedessenceofhatred"]=655; -_NTIPAliasClassID["bet"]=656; _NTIPAliasClassID["burningessenceofterror"]=656; -_NTIPAliasClassID["fed"]=657; _NTIPAliasClassID["festeringessenceofdestruction"]=657; -_NTIPAliasClassID["std"]=658; _NTIPAliasClassID["standardofheroes"]=658; +var NTIPAliasClassID = {}; +NTIPAliasClassID["hax"] = 0; NTIPAliasClassID["handaxe"] = 0; +NTIPAliasClassID["axe"] = 1; +NTIPAliasClassID["2ax"] = 2; NTIPAliasClassID["doubleaxe"] = 2; +NTIPAliasClassID["mpi"] = 3; NTIPAliasClassID["militarypick"] = 3; +NTIPAliasClassID["wax"] = 4; NTIPAliasClassID["waraxe"] = 4; +NTIPAliasClassID["lax"] = 5; NTIPAliasClassID["largeaxe"] = 5; +NTIPAliasClassID["bax"] = 6; NTIPAliasClassID["broadaxe"] = 6; +NTIPAliasClassID["btx"] = 7; NTIPAliasClassID["battleaxe"] = 7; +NTIPAliasClassID["gax"] = 8; NTIPAliasClassID["greataxe"] = 8; +NTIPAliasClassID["gix"] = 9; NTIPAliasClassID["giantaxe"] = 9; +NTIPAliasClassID["wnd"] = 10; NTIPAliasClassID["wand"] = 10; +NTIPAliasClassID["ywn"] = 11; NTIPAliasClassID["yewwand"] = 11; +NTIPAliasClassID["bwn"] = 12; NTIPAliasClassID["bonewand"] = 12; +NTIPAliasClassID["gwn"] = 13; NTIPAliasClassID["grimwand"] = 13; +NTIPAliasClassID["clb"] = 14; NTIPAliasClassID["club"] = 14; +NTIPAliasClassID["scp"] = 15; NTIPAliasClassID["scepter"] = 15; +NTIPAliasClassID["gsc"] = 16; NTIPAliasClassID["grandscepter"] = 16; +NTIPAliasClassID["wsp"] = 17; NTIPAliasClassID["warscepter"] = 17; +NTIPAliasClassID["spc"] = 18; NTIPAliasClassID["spikedclub"] = 18; +NTIPAliasClassID["mac"] = 19; NTIPAliasClassID["mace"] = 19; +NTIPAliasClassID["mst"] = 20; NTIPAliasClassID["morningstar"] = 20; +NTIPAliasClassID["fla"] = 21; NTIPAliasClassID["flail"] = 21; +NTIPAliasClassID["whm"] = 22; NTIPAliasClassID["warhammer"] = 22; +NTIPAliasClassID["mau"] = 23; NTIPAliasClassID["maul"] = 23; +NTIPAliasClassID["gma"] = 24; NTIPAliasClassID["greatmaul"] = 24; +NTIPAliasClassID["ssd"] = 25; NTIPAliasClassID["shortsword"] = 25; +NTIPAliasClassID["scm"] = 26; NTIPAliasClassID["scimitar"] = 26; +NTIPAliasClassID["sbr"] = 27; NTIPAliasClassID["sabre"] = 27; +NTIPAliasClassID["flc"] = 28; NTIPAliasClassID["falchion"] = 28; +NTIPAliasClassID["crs"] = 29; NTIPAliasClassID["crystalsword"] = 29; +NTIPAliasClassID["bsd"] = 30; NTIPAliasClassID["broadsword"] = 30; +NTIPAliasClassID["lsd"] = 31; NTIPAliasClassID["longsword"] = 31; +NTIPAliasClassID["wsd"] = 32; NTIPAliasClassID["warsword"] = 32; +NTIPAliasClassID["2hs"] = 33; NTIPAliasClassID["twohandedsword"] = 33; +NTIPAliasClassID["clm"] = 34; NTIPAliasClassID["claymore"] = 34; +NTIPAliasClassID["gis"] = 35; NTIPAliasClassID["giantsword"] = 35; +NTIPAliasClassID["bsw"] = 36; NTIPAliasClassID["bastardsword"] = 36; +NTIPAliasClassID["flb"] = 37; NTIPAliasClassID["flamberge"] = 37; +NTIPAliasClassID["gsd"] = 38; NTIPAliasClassID["greatsword"] = 38; +NTIPAliasClassID["dgr"] = 39; NTIPAliasClassID["dagger"] = 39; +NTIPAliasClassID["dir"] = 40; NTIPAliasClassID["dirk"] = 40; +NTIPAliasClassID["kri"] = 41; NTIPAliasClassID["kris"] = 41; +NTIPAliasClassID["bld"] = 42; NTIPAliasClassID["blade"] = 42; +NTIPAliasClassID["tkf"] = 43; NTIPAliasClassID["throwingknife"] = 43; +NTIPAliasClassID["tax"] = 44; NTIPAliasClassID["throwingaxe"] = 44; +NTIPAliasClassID["bkf"] = 45; NTIPAliasClassID["balancedknife"] = 45; +NTIPAliasClassID["bal"] = 46; NTIPAliasClassID["balancedaxe"] = 46; +NTIPAliasClassID["jav"] = 47; NTIPAliasClassID["javelin"] = 47; +NTIPAliasClassID["pil"] = 48; NTIPAliasClassID["pilum"] = 48; +NTIPAliasClassID["ssp"] = 49; NTIPAliasClassID["shortspear"] = 49; +NTIPAliasClassID["glv"] = 50; NTIPAliasClassID["glaive"] = 50; +NTIPAliasClassID["tsp"] = 51; NTIPAliasClassID["throwingspear"] = 51; +NTIPAliasClassID["spr"] = 52; NTIPAliasClassID["spear"] = 52; +NTIPAliasClassID["tri"] = 53; NTIPAliasClassID["trident"] = 53; +NTIPAliasClassID["brn"] = 54; NTIPAliasClassID["brandistock"] = 54; +NTIPAliasClassID["spt"] = 55; NTIPAliasClassID["spetum"] = 55; +NTIPAliasClassID["pik"] = 56; NTIPAliasClassID["pike"] = 56; +NTIPAliasClassID["bar"] = 57; NTIPAliasClassID["bardiche"] = 57; +NTIPAliasClassID["vou"] = 58; NTIPAliasClassID["voulge"] = 58; +NTIPAliasClassID["scy"] = 59; NTIPAliasClassID["scythe"] = 59; +NTIPAliasClassID["pax"] = 60; NTIPAliasClassID["poleaxe"] = 60; +NTIPAliasClassID["hal"] = 61; NTIPAliasClassID["halberd"] = 61; +NTIPAliasClassID["wsc"] = 62; NTIPAliasClassID["warscythe"] = 62; +NTIPAliasClassID["sst"] = 63; NTIPAliasClassID["shortstaff"] = 63; +NTIPAliasClassID["lst"] = 64; NTIPAliasClassID["longstaff"] = 64; +NTIPAliasClassID["cst"] = 65; NTIPAliasClassID["gnarledstaff"] = 65; +NTIPAliasClassID["bst"] = 66; NTIPAliasClassID["battlestaff"] = 66; +NTIPAliasClassID["wst"] = 67; NTIPAliasClassID["warstaff"] = 67; +NTIPAliasClassID["sbw"] = 68; NTIPAliasClassID["shortbow"] = 68; +NTIPAliasClassID["hbw"] = 69; NTIPAliasClassID["hunter'sbow"] = 69; +NTIPAliasClassID["lbw"] = 70; NTIPAliasClassID["longbow"] = 70; +NTIPAliasClassID["cbw"] = 71; NTIPAliasClassID["compositebow"] = 71; +NTIPAliasClassID["sbb"] = 72; NTIPAliasClassID["shortbattlebow"] = 72; +NTIPAliasClassID["lbb"] = 73; NTIPAliasClassID["longbattlebow"] = 73; +NTIPAliasClassID["swb"] = 74; NTIPAliasClassID["shortwarbow"] = 74; +NTIPAliasClassID["lwb"] = 75; NTIPAliasClassID["longwarbow"] = 75; +NTIPAliasClassID["lxb"] = 76; NTIPAliasClassID["lightcrossbow"] = 76; +NTIPAliasClassID["mxb"] = 77; NTIPAliasClassID["crossbow"] = 77; +NTIPAliasClassID["hxb"] = 78; NTIPAliasClassID["heavycrossbow"] = 78; +NTIPAliasClassID["rxb"] = 79; NTIPAliasClassID["repeatingcrossbow"] = 79; +NTIPAliasClassID["gps"] = 80; NTIPAliasClassID["rancidgaspotion"] = 80; +NTIPAliasClassID["ops"] = 81; NTIPAliasClassID["oilpotion"] = 81; +NTIPAliasClassID["gpm"] = 82; NTIPAliasClassID["chokinggaspotion"] = 82; +NTIPAliasClassID["opm"] = 83; NTIPAliasClassID["explodingpotion"] = 83; +NTIPAliasClassID["gpl"] = 84; NTIPAliasClassID["stranglinggaspotion"] = 84; +NTIPAliasClassID["opl"] = 85; NTIPAliasClassID["fulminatingpotion"] = 85; +NTIPAliasClassID["d33"] = 86; NTIPAliasClassID["decoygidbinn"] = 86; +NTIPAliasClassID["g33"] = 87; NTIPAliasClassID["thegidbinn"] = 87; +NTIPAliasClassID["leg"] = 88; NTIPAliasClassID["wirt'sleg"] = 88; +NTIPAliasClassID["hdm"] = 89; NTIPAliasClassID["horadricmalus"] = 89; +NTIPAliasClassID["hfh"] = 90; NTIPAliasClassID["hellforgehammer"] = 90; +NTIPAliasClassID["hst"] = 91; NTIPAliasClassID["horadricstaff"] = 91; +NTIPAliasClassID["msf"] = 92; NTIPAliasClassID["shaftofthehoradricstaff"] = 92; +NTIPAliasClassID["9ha"] = 93; NTIPAliasClassID["hatchet"] = 93; +NTIPAliasClassID["9ax"] = 94; NTIPAliasClassID["cleaver"] = 94; +NTIPAliasClassID["92a"] = 95; NTIPAliasClassID["twinaxe"] = 95; +NTIPAliasClassID["9mp"] = 96; NTIPAliasClassID["crowbill"] = 96; +NTIPAliasClassID["9wa"] = 97; NTIPAliasClassID["naga"] = 97; +NTIPAliasClassID["9la"] = 98; NTIPAliasClassID["militaryaxe"] = 98; +NTIPAliasClassID["9ba"] = 99; NTIPAliasClassID["beardedaxe"] = 99; +NTIPAliasClassID["9bt"] = 100; NTIPAliasClassID["tabar"] = 100; +NTIPAliasClassID["9ga"] = 101; NTIPAliasClassID["gothicaxe"] = 101; +NTIPAliasClassID["9gi"] = 102; NTIPAliasClassID["ancientaxe"] = 102; +NTIPAliasClassID["9wn"] = 103; NTIPAliasClassID["burntwand"] = 103; +NTIPAliasClassID["9yw"] = 104; NTIPAliasClassID["petrifiedwand"] = 104; +NTIPAliasClassID["9bw"] = 105; NTIPAliasClassID["tombwand"] = 105; +NTIPAliasClassID["9gw"] = 106; NTIPAliasClassID["gravewand"] = 106; +NTIPAliasClassID["9cl"] = 107; NTIPAliasClassID["cudgel"] = 107; +NTIPAliasClassID["9sc"] = 108; NTIPAliasClassID["runescepter"] = 108; +NTIPAliasClassID["9qs"] = 109; NTIPAliasClassID["holywatersprinkler"] = 109; +NTIPAliasClassID["9ws"] = 110; NTIPAliasClassID["divinescepter"] = 110; +NTIPAliasClassID["9sp"] = 111; NTIPAliasClassID["barbedclub"] = 111; +NTIPAliasClassID["9ma"] = 112; NTIPAliasClassID["flangedmace"] = 112; +NTIPAliasClassID["9mt"] = 113; NTIPAliasClassID["jaggedstar"] = 113; +NTIPAliasClassID["9fl"] = 114; NTIPAliasClassID["knout"] = 114; +NTIPAliasClassID["9wh"] = 115; NTIPAliasClassID["battlehammer"] = 115; +NTIPAliasClassID["9m9"] = 116; NTIPAliasClassID["warclub"] = 116; +NTIPAliasClassID["9gm"] = 117; NTIPAliasClassID["marteldefer"] = 117; +NTIPAliasClassID["9ss"] = 118; NTIPAliasClassID["gladius"] = 118; +NTIPAliasClassID["9sm"] = 119; NTIPAliasClassID["cutlass"] = 119; +NTIPAliasClassID["9sb"] = 120; NTIPAliasClassID["shamshir"] = 120; +NTIPAliasClassID["9fc"] = 121; NTIPAliasClassID["tulwar"] = 121; +NTIPAliasClassID["9cr"] = 122; NTIPAliasClassID["dimensionalblade"] = 122; +NTIPAliasClassID["9bs"] = 123; NTIPAliasClassID["battlesword"] = 123; +NTIPAliasClassID["9ls"] = 124; NTIPAliasClassID["runesword"] = 124; +NTIPAliasClassID["9wd"] = 125; NTIPAliasClassID["ancientsword"] = 125; +NTIPAliasClassID["92h"] = 126; NTIPAliasClassID["espandon"] = 126; +NTIPAliasClassID["9cm"] = 127; NTIPAliasClassID["dacianfalx"] = 127; +NTIPAliasClassID["9gs"] = 128; NTIPAliasClassID["tusksword"] = 128; +NTIPAliasClassID["9b9"] = 129; NTIPAliasClassID["gothicsword"] = 129; +NTIPAliasClassID["9fb"] = 130; NTIPAliasClassID["zweihander"] = 130; +NTIPAliasClassID["9gd"] = 131; NTIPAliasClassID["executionersword"] = 131; +NTIPAliasClassID["9dg"] = 132; NTIPAliasClassID["poignard"] = 132; +NTIPAliasClassID["9di"] = 133; NTIPAliasClassID["rondel"] = 133; +NTIPAliasClassID["9kr"] = 134; NTIPAliasClassID["cinquedeas"] = 134; +NTIPAliasClassID["9bl"] = 135; NTIPAliasClassID["stiletto"] = 135; +NTIPAliasClassID["9tk"] = 136; NTIPAliasClassID["battledart"] = 136; +NTIPAliasClassID["9ta"] = 137; NTIPAliasClassID["francisca"] = 137; +NTIPAliasClassID["9bk"] = 138; NTIPAliasClassID["wardart"] = 138; +NTIPAliasClassID["9b8"] = 139; NTIPAliasClassID["hurlbat"] = 139; +NTIPAliasClassID["9ja"] = 140; NTIPAliasClassID["warjavelin"] = 140; +NTIPAliasClassID["9pi"] = 141; NTIPAliasClassID["greatpilum"] = 141; +NTIPAliasClassID["9s9"] = 142; NTIPAliasClassID["simbilan"] = 142; +NTIPAliasClassID["9gl"] = 143; NTIPAliasClassID["spiculum"] = 143; +NTIPAliasClassID["9ts"] = 144; NTIPAliasClassID["harpoon"] = 144; +NTIPAliasClassID["9sr"] = 145; NTIPAliasClassID["warspear"] = 145; +NTIPAliasClassID["9tr"] = 146; NTIPAliasClassID["fuscina"] = 146; +NTIPAliasClassID["9br"] = 147; NTIPAliasClassID["warfork"] = 147; +NTIPAliasClassID["9st"] = 148; NTIPAliasClassID["yari"] = 148; +NTIPAliasClassID["9p9"] = 149; NTIPAliasClassID["lance"] = 149; +NTIPAliasClassID["9b7"] = 150; NTIPAliasClassID["lochaberaxe"] = 150; +NTIPAliasClassID["9vo"] = 151; NTIPAliasClassID["bill"] = 151; +NTIPAliasClassID["9s8"] = 152; NTIPAliasClassID["battlescythe"] = 152; +NTIPAliasClassID["9pa"] = 153; NTIPAliasClassID["partizan"] = 153; +NTIPAliasClassID["9h9"] = 154; NTIPAliasClassID["becdecorbin"] = 154; +NTIPAliasClassID["9wc"] = 155; NTIPAliasClassID["grimscythe"] = 155; +NTIPAliasClassID["8ss"] = 156; NTIPAliasClassID["jostaff"] = 156; +NTIPAliasClassID["8ls"] = 157; NTIPAliasClassID["quarterstaff"] = 157; +NTIPAliasClassID["8cs"] = 158; NTIPAliasClassID["cedarstaff"] = 158; +NTIPAliasClassID["8bs"] = 159; NTIPAliasClassID["gothicstaff"] = 159; +NTIPAliasClassID["8ws"] = 160; NTIPAliasClassID["runestaff"] = 160; +NTIPAliasClassID["8sb"] = 161; NTIPAliasClassID["edgebow"] = 161; +NTIPAliasClassID["8hb"] = 162; NTIPAliasClassID["razorbow"] = 162; +NTIPAliasClassID["8lb"] = 163; NTIPAliasClassID["cedarbow"] = 163; +NTIPAliasClassID["8cb"] = 164; NTIPAliasClassID["doublebow"] = 164; +NTIPAliasClassID["8s8"] = 165; NTIPAliasClassID["shortsiegebow"] = 165; +NTIPAliasClassID["8l8"] = 166; NTIPAliasClassID["largesiegebow"] = 166; +NTIPAliasClassID["8sw"] = 167; NTIPAliasClassID["runebow"] = 167; +NTIPAliasClassID["8lw"] = 168; NTIPAliasClassID["gothicbow"] = 168; +NTIPAliasClassID["8lx"] = 169; NTIPAliasClassID["arbalest"] = 169; +NTIPAliasClassID["8mx"] = 170; NTIPAliasClassID["siegecrossbow"] = 170; +NTIPAliasClassID["8hx"] = 171; NTIPAliasClassID["ballista"] = 171; +NTIPAliasClassID["8rx"] = 172; NTIPAliasClassID["chukonu"] = 172; +NTIPAliasClassID["qf1"] = 173; NTIPAliasClassID["khalim'sflail"] = 173; +NTIPAliasClassID["qf2"] = 174; NTIPAliasClassID["khalim'swill"] = 174; +NTIPAliasClassID["ktr"] = 175; NTIPAliasClassID["katar"] = 175; +NTIPAliasClassID["wrb"] = 176; NTIPAliasClassID["wristblade"] = 176; +NTIPAliasClassID["axf"] = 177; NTIPAliasClassID["hatchethands"] = 177; +NTIPAliasClassID["ces"] = 178; NTIPAliasClassID["cestus"] = 178; +NTIPAliasClassID["clw"] = 179; NTIPAliasClassID["claws"] = 179; +NTIPAliasClassID["btl"] = 180; NTIPAliasClassID["bladetalons"] = 180; +NTIPAliasClassID["skr"] = 181; NTIPAliasClassID["scissorskatar"] = 181; +NTIPAliasClassID["9ar"] = 182; NTIPAliasClassID["quhab"] = 182; +NTIPAliasClassID["9wb"] = 183; NTIPAliasClassID["wristspike"] = 183; +NTIPAliasClassID["9xf"] = 184; NTIPAliasClassID["fascia"] = 184; +NTIPAliasClassID["9cs"] = 185; NTIPAliasClassID["handscythe"] = 185; +NTIPAliasClassID["9lw"] = 186; NTIPAliasClassID["greaterclaws"] = 186; +NTIPAliasClassID["9tw"] = 187; NTIPAliasClassID["greatertalons"] = 187; +NTIPAliasClassID["9qr"] = 188; NTIPAliasClassID["scissorsquhab"] = 188; +NTIPAliasClassID["7ar"] = 189; NTIPAliasClassID["suwayyah"] = 189; +NTIPAliasClassID["7wb"] = 190; NTIPAliasClassID["wristsword"] = 190; +NTIPAliasClassID["7xf"] = 191; NTIPAliasClassID["warfist"] = 191; +NTIPAliasClassID["7cs"] = 192; NTIPAliasClassID["battlecestus"] = 192; +NTIPAliasClassID["7lw"] = 193; NTIPAliasClassID["feralclaws"] = 193; +NTIPAliasClassID["7tw"] = 194; NTIPAliasClassID["runictalons"] = 194; +NTIPAliasClassID["7qr"] = 195; NTIPAliasClassID["scissorssuwayyah"] = 195; +NTIPAliasClassID["7ha"] = 196; NTIPAliasClassID["tomahawk"] = 196; +NTIPAliasClassID["7ax"] = 197; NTIPAliasClassID["smallcrescent"] = 197; +NTIPAliasClassID["72a"] = 198; NTIPAliasClassID["ettinaxe"] = 198; +NTIPAliasClassID["7mp"] = 199; NTIPAliasClassID["warspike"] = 199; +NTIPAliasClassID["7wa"] = 200; NTIPAliasClassID["berserkeraxe"] = 200; +NTIPAliasClassID["7la"] = 201; NTIPAliasClassID["feralaxe"] = 201; +NTIPAliasClassID["7ba"] = 202; NTIPAliasClassID["silveredgedaxe"] = 202; +NTIPAliasClassID["7bt"] = 203; NTIPAliasClassID["decapitator"] = 203; +NTIPAliasClassID["7ga"] = 204; NTIPAliasClassID["championaxe"] = 204; +NTIPAliasClassID["7gi"] = 205; NTIPAliasClassID["gloriousaxe"] = 205; +NTIPAliasClassID["7wn"] = 206; NTIPAliasClassID["polishedwand"] = 206; +NTIPAliasClassID["7yw"] = 207; NTIPAliasClassID["ghostwand"] = 207; +NTIPAliasClassID["7bw"] = 208; NTIPAliasClassID["lichwand"] = 208; +NTIPAliasClassID["7gw"] = 209; NTIPAliasClassID["unearthedwand"] = 209; +NTIPAliasClassID["7cl"] = 210; NTIPAliasClassID["truncheon"] = 210; +NTIPAliasClassID["7sc"] = 211; NTIPAliasClassID["mightyscepter"] = 211; +NTIPAliasClassID["7qs"] = 212; NTIPAliasClassID["seraphrod"] = 212; +NTIPAliasClassID["7ws"] = 213; NTIPAliasClassID["caduceus"] = 213; +NTIPAliasClassID["7sp"] = 214; NTIPAliasClassID["tyrantclub"] = 214; +NTIPAliasClassID["7ma"] = 215; NTIPAliasClassID["reinforcedmace"] = 215; +NTIPAliasClassID["7mt"] = 216; NTIPAliasClassID["devilstar"] = 216; +NTIPAliasClassID["7fl"] = 217; NTIPAliasClassID["scourge"] = 217; +NTIPAliasClassID["7wh"] = 218; NTIPAliasClassID["legendarymallet"] = 218; +NTIPAliasClassID["7m7"] = 219; NTIPAliasClassID["ogremaul"] = 219; +NTIPAliasClassID["7gm"] = 220; NTIPAliasClassID["thundermaul"] = 220; +NTIPAliasClassID["7ss"] = 221; NTIPAliasClassID["falcata"] = 221; +NTIPAliasClassID["7sm"] = 222; NTIPAliasClassID["ataghan"] = 222; +NTIPAliasClassID["7sb"] = 223; NTIPAliasClassID["elegantblade"] = 223; +NTIPAliasClassID["7fc"] = 224; NTIPAliasClassID["hydraedge"] = 224; +NTIPAliasClassID["7cr"] = 225; NTIPAliasClassID["phaseblade"] = 225; +NTIPAliasClassID["7bs"] = 226; NTIPAliasClassID["conquestsword"] = 226; +NTIPAliasClassID["7ls"] = 227; NTIPAliasClassID["crypticsword"] = 227; +NTIPAliasClassID["7wd"] = 228; NTIPAliasClassID["mythicalsword"] = 228; +NTIPAliasClassID["72h"] = 229; NTIPAliasClassID["legendsword"] = 229; +NTIPAliasClassID["7cm"] = 230; NTIPAliasClassID["highlandblade"] = 230; +NTIPAliasClassID["7gs"] = 231; NTIPAliasClassID["balrogblade"] = 231; +NTIPAliasClassID["7b7"] = 232; NTIPAliasClassID["championsword"] = 232; +NTIPAliasClassID["7fb"] = 233; NTIPAliasClassID["colossussword"] = 233; +NTIPAliasClassID["7gd"] = 234; NTIPAliasClassID["colossusblade"] = 234; +NTIPAliasClassID["7dg"] = 235; NTIPAliasClassID["boneknife"] = 235; +NTIPAliasClassID["7di"] = 236; NTIPAliasClassID["mithrilpoint"] = 236; +NTIPAliasClassID["7kr"] = 237; NTIPAliasClassID["fangedknife"] = 237; +NTIPAliasClassID["7bl"] = 238; NTIPAliasClassID["legendspike"] = 238; +NTIPAliasClassID["7tk"] = 239; NTIPAliasClassID["flyingknife"] = 239; +NTIPAliasClassID["7ta"] = 240; NTIPAliasClassID["flyingaxe"] = 240; +NTIPAliasClassID["7bk"] = 241; NTIPAliasClassID["wingedknife"] = 241; +NTIPAliasClassID["7b8"] = 242; NTIPAliasClassID["wingedaxe"] = 242; +NTIPAliasClassID["7ja"] = 243; NTIPAliasClassID["hyperionjavelin"] = 243; +NTIPAliasClassID["7pi"] = 244; NTIPAliasClassID["stygianpilum"] = 244; +NTIPAliasClassID["7s7"] = 245; NTIPAliasClassID["balrogspear"] = 245; +NTIPAliasClassID["7gl"] = 246; NTIPAliasClassID["ghostglaive"] = 246; +NTIPAliasClassID["7ts"] = 247; NTIPAliasClassID["wingedharpoon"] = 247; +NTIPAliasClassID["7sr"] = 248; NTIPAliasClassID["hyperionspear"] = 248; +NTIPAliasClassID["7tr"] = 249; NTIPAliasClassID["stygianpike"] = 249; +NTIPAliasClassID["7br"] = 250; NTIPAliasClassID["mancatcher"] = 250; +NTIPAliasClassID["7st"] = 251; NTIPAliasClassID["ghostspear"] = 251; +NTIPAliasClassID["7p7"] = 252; NTIPAliasClassID["warpike"] = 252; +NTIPAliasClassID["7o7"] = 253; NTIPAliasClassID["ogreaxe"] = 253; +NTIPAliasClassID["7vo"] = 254; NTIPAliasClassID["colossusvoulge"] = 254; +NTIPAliasClassID["7s8"] = 255; NTIPAliasClassID["thresher"] = 255; +NTIPAliasClassID["7pa"] = 256; NTIPAliasClassID["crypticaxe"] = 256; +NTIPAliasClassID["7h7"] = 257; NTIPAliasClassID["greatpoleaxe"] = 257; +NTIPAliasClassID["7wc"] = 258; NTIPAliasClassID["giantthresher"] = 258; +NTIPAliasClassID["6ss"] = 259; NTIPAliasClassID["walkingstick"] = 259; +NTIPAliasClassID["6ls"] = 260; NTIPAliasClassID["stalagmite"] = 260; +NTIPAliasClassID["6cs"] = 261; NTIPAliasClassID["elderstaff"] = 261; +NTIPAliasClassID["6bs"] = 262; NTIPAliasClassID["shillelagh"] = 262; +NTIPAliasClassID["6ws"] = 263; NTIPAliasClassID["archonstaff"] = 263; +NTIPAliasClassID["6sb"] = 264; NTIPAliasClassID["spiderbow"] = 264; +NTIPAliasClassID["6hb"] = 265; NTIPAliasClassID["bladebow"] = 265; +NTIPAliasClassID["6lb"] = 266; NTIPAliasClassID["shadowbow"] = 266; +NTIPAliasClassID["6cb"] = 267; NTIPAliasClassID["greatbow"] = 267; +NTIPAliasClassID["6s7"] = 268; NTIPAliasClassID["diamondbow"] = 268; +NTIPAliasClassID["6l7"] = 269; NTIPAliasClassID["crusaderbow"] = 269; +NTIPAliasClassID["6sw"] = 270; NTIPAliasClassID["wardbow"] = 270; +NTIPAliasClassID["6lw"] = 271; NTIPAliasClassID["hydrabow"] = 271; +NTIPAliasClassID["6lx"] = 272; NTIPAliasClassID["pelletbow"] = 272; +NTIPAliasClassID["6mx"] = 273; NTIPAliasClassID["gorgoncrossbow"] = 273; +NTIPAliasClassID["6hx"] = 274; NTIPAliasClassID["colossuscrossbow"] = 274; +NTIPAliasClassID["6rx"] = 275; NTIPAliasClassID["demoncrossbow"] = 275; +NTIPAliasClassID["ob1"] = 276; NTIPAliasClassID["eagleorb"] = 276; +NTIPAliasClassID["ob2"] = 277; NTIPAliasClassID["sacredglobe"] = 277; +NTIPAliasClassID["ob3"] = 278; NTIPAliasClassID["smokedsphere"] = 278; +NTIPAliasClassID["ob4"] = 279; NTIPAliasClassID["claspedorb"] = 279; +NTIPAliasClassID["ob5"] = 280; NTIPAliasClassID["jared'sstone"] = 280; +NTIPAliasClassID["am1"] = 281; NTIPAliasClassID["stagbow"] = 281; +NTIPAliasClassID["am2"] = 282; NTIPAliasClassID["reflexbow"] = 282; +NTIPAliasClassID["am3"] = 283; NTIPAliasClassID["maidenspear"] = 283; +NTIPAliasClassID["am4"] = 284; NTIPAliasClassID["maidenpike"] = 284; +NTIPAliasClassID["am5"] = 285; NTIPAliasClassID["maidenjavelin"] = 285; +NTIPAliasClassID["ob6"] = 286; NTIPAliasClassID["glowingorb"] = 286; +NTIPAliasClassID["ob7"] = 287; NTIPAliasClassID["crystallineglobe"] = 287; +NTIPAliasClassID["ob8"] = 288; NTIPAliasClassID["cloudysphere"] = 288; +NTIPAliasClassID["ob9"] = 289; NTIPAliasClassID["sparklingball"] = 289; +NTIPAliasClassID["oba"] = 290; NTIPAliasClassID["swirlingcrystal"] = 290; +NTIPAliasClassID["am6"] = 291; NTIPAliasClassID["ashwoodbow"] = 291; +NTIPAliasClassID["am7"] = 292; NTIPAliasClassID["ceremonialbow"] = 292; +NTIPAliasClassID["am8"] = 293; NTIPAliasClassID["ceremonialspear"] = 293; +NTIPAliasClassID["am9"] = 294; NTIPAliasClassID["ceremonialpike"] = 294; +NTIPAliasClassID["ama"] = 295; NTIPAliasClassID["ceremonialjavelin"] = 295; +NTIPAliasClassID["obb"] = 296; NTIPAliasClassID["heavenlystone"] = 296; +NTIPAliasClassID["obc"] = 297; NTIPAliasClassID["eldritchorb"] = 297; +NTIPAliasClassID["obd"] = 298; NTIPAliasClassID["demonheart"] = 298; +NTIPAliasClassID["obe"] = 299; NTIPAliasClassID["vortexorb"] = 299; +NTIPAliasClassID["obf"] = 300; NTIPAliasClassID["dimensionalshard"] = 300; +NTIPAliasClassID["amb"] = 301; NTIPAliasClassID["matriarchalbow"] = 301; +NTIPAliasClassID["amc"] = 302; NTIPAliasClassID["grandmatronbow"] = 302; +NTIPAliasClassID["amd"] = 303; NTIPAliasClassID["matriarchalspear"] = 303; +NTIPAliasClassID["ame"] = 304; NTIPAliasClassID["matriarchalpike"] = 304; +NTIPAliasClassID["amf"] = 305; NTIPAliasClassID["matriarchaljavelin"] = 305; +NTIPAliasClassID["cap"] = 306; +NTIPAliasClassID["skp"] = 307; NTIPAliasClassID["skullcap"] = 307; +NTIPAliasClassID["hlm"] = 308; NTIPAliasClassID["helm"] = 308; +NTIPAliasClassID["fhl"] = 309; NTIPAliasClassID["fullhelm"] = 309; +NTIPAliasClassID["ghm"] = 310; NTIPAliasClassID["greathelm"] = 310; +NTIPAliasClassID["crn"] = 311; NTIPAliasClassID["crown"] = 311; +NTIPAliasClassID["msk"] = 312; NTIPAliasClassID["mask"] = 312; +NTIPAliasClassID["qui"] = 313; NTIPAliasClassID["quiltedarmor"] = 313; +NTIPAliasClassID["lea"] = 314; NTIPAliasClassID["leatherarmor"] = 314; +NTIPAliasClassID["hla"] = 315; NTIPAliasClassID["hardleatherarmor"] = 315; +NTIPAliasClassID["stu"] = 316; NTIPAliasClassID["studdedleather"] = 316; +NTIPAliasClassID["rng"] = 317; NTIPAliasClassID["ringmail"] = 317; +NTIPAliasClassID["scl"] = 318; NTIPAliasClassID["scalemail"] = 318; +NTIPAliasClassID["chn"] = 319; NTIPAliasClassID["chainmail"] = 319; +NTIPAliasClassID["brs"] = 320; NTIPAliasClassID["breastplate"] = 320; +NTIPAliasClassID["spl"] = 321; NTIPAliasClassID["splintmail"] = 321; +NTIPAliasClassID["plt"] = 322; NTIPAliasClassID["platemail"] = 322; +NTIPAliasClassID["fld"] = 323; NTIPAliasClassID["fieldplate"] = 323; +NTIPAliasClassID["gth"] = 324; NTIPAliasClassID["gothicplate"] = 324; +NTIPAliasClassID["ful"] = 325; NTIPAliasClassID["fullplatemail"] = 325; +NTIPAliasClassID["aar"] = 326; NTIPAliasClassID["ancientarmor"] = 326; +NTIPAliasClassID["ltp"] = 327; NTIPAliasClassID["lightplate"] = 327; +NTIPAliasClassID["buc"] = 328; NTIPAliasClassID["buckler"] = 328; +NTIPAliasClassID["sml"] = 329; NTIPAliasClassID["smallshield"] = 329; +NTIPAliasClassID["lrg"] = 330; NTIPAliasClassID["largeshield"] = 330; +NTIPAliasClassID["kit"] = 331; NTIPAliasClassID["kiteshield"] = 331; +NTIPAliasClassID["tow"] = 332; NTIPAliasClassID["towershield"] = 332; +NTIPAliasClassID["gts"] = 333; NTIPAliasClassID["gothicshield"] = 333; +NTIPAliasClassID["lgl"] = 334; NTIPAliasClassID["leathergloves"] = 334; +NTIPAliasClassID["vgl"] = 335; NTIPAliasClassID["heavygloves"] = 335; +NTIPAliasClassID["mgl"] = 336; NTIPAliasClassID["chaingloves"] = 336; +NTIPAliasClassID["tgl"] = 337; NTIPAliasClassID["lightgauntlets"] = 337; +NTIPAliasClassID["hgl"] = 338; NTIPAliasClassID["gauntlets"] = 338; +NTIPAliasClassID["lbt"] = 339; NTIPAliasClassID["boots"] = 339; +NTIPAliasClassID["vbt"] = 340; NTIPAliasClassID["heavyboots"] = 340; +NTIPAliasClassID["mbt"] = 341; NTIPAliasClassID["chainboots"] = 341; +NTIPAliasClassID["tbt"] = 342; NTIPAliasClassID["lightplatedboots"] = 342; +NTIPAliasClassID["hbt"] = 343; NTIPAliasClassID["greaves"] = 343; +NTIPAliasClassID["lbl"] = 344; NTIPAliasClassID["sash"] = 344; +NTIPAliasClassID["vbl"] = 345; NTIPAliasClassID["lightbelt"] = 345; +NTIPAliasClassID["mbl"] = 346; NTIPAliasClassID["belt"] = 346; +NTIPAliasClassID["tbl"] = 347; NTIPAliasClassID["heavybelt"] = 347; +NTIPAliasClassID["hbl"] = 348; NTIPAliasClassID["platedbelt"] = 348; +NTIPAliasClassID["bhm"] = 349; NTIPAliasClassID["bonehelm"] = 349; +NTIPAliasClassID["bsh"] = 350; NTIPAliasClassID["boneshield"] = 350; +NTIPAliasClassID["spk"] = 351; NTIPAliasClassID["spikedshield"] = 351; +NTIPAliasClassID["xap"] = 352; NTIPAliasClassID["warhat"] = 352; +NTIPAliasClassID["xkp"] = 353; NTIPAliasClassID["sallet"] = 353; +NTIPAliasClassID["xlm"] = 354; NTIPAliasClassID["casque"] = 354; +NTIPAliasClassID["xhl"] = 355; NTIPAliasClassID["basinet"] = 355; +NTIPAliasClassID["xhm"] = 356; NTIPAliasClassID["wingedhelm"] = 356; +NTIPAliasClassID["xrn"] = 357; NTIPAliasClassID["grandcrown"] = 357; +NTIPAliasClassID["xsk"] = 358; NTIPAliasClassID["deathmask"] = 358; +NTIPAliasClassID["xui"] = 359; NTIPAliasClassID["ghostarmor"] = 359; +NTIPAliasClassID["xea"] = 360; NTIPAliasClassID["serpentskinarmor"] = 360; +NTIPAliasClassID["xla"] = 361; NTIPAliasClassID["demonhidearmor"] = 361; +NTIPAliasClassID["xtu"] = 362; NTIPAliasClassID["trellisedarmor"] = 362; +NTIPAliasClassID["xng"] = 363; NTIPAliasClassID["linkedmail"] = 363; +NTIPAliasClassID["xcl"] = 364; NTIPAliasClassID["tigulatedmail"] = 364; +NTIPAliasClassID["xhn"] = 365; NTIPAliasClassID["mesharmor"] = 365; +NTIPAliasClassID["xrs"] = 366; NTIPAliasClassID["cuirass"] = 366; +NTIPAliasClassID["xpl"] = 367; NTIPAliasClassID["russetarmor"] = 367; +NTIPAliasClassID["xlt"] = 368; NTIPAliasClassID["templarcoat"] = 368; +NTIPAliasClassID["xld"] = 369; NTIPAliasClassID["sharktootharmor"] = 369; +NTIPAliasClassID["xth"] = 370; NTIPAliasClassID["embossedplate"] = 370; +NTIPAliasClassID["xul"] = 371; NTIPAliasClassID["chaosarmor"] = 371; +NTIPAliasClassID["xar"] = 372; NTIPAliasClassID["ornateplate"] = 372; +NTIPAliasClassID["xtp"] = 373; NTIPAliasClassID["mageplate"] = 373; +NTIPAliasClassID["xuc"] = 374; NTIPAliasClassID["defender"] = 374; +NTIPAliasClassID["xml"] = 375; NTIPAliasClassID["roundshield"] = 375; +NTIPAliasClassID["xrg"] = 376; NTIPAliasClassID["scutum"] = 376; +NTIPAliasClassID["xit"] = 377; NTIPAliasClassID["dragonshield"] = 377; +NTIPAliasClassID["xow"] = 378; NTIPAliasClassID["pavise"] = 378; +NTIPAliasClassID["xts"] = 379; NTIPAliasClassID["ancientshield"] = 379; +NTIPAliasClassID["xlg"] = 380; NTIPAliasClassID["demonhidegloves"] = 380; +NTIPAliasClassID["xvg"] = 381; NTIPAliasClassID["sharkskingloves"] = 381; +NTIPAliasClassID["xmg"] = 382; NTIPAliasClassID["heavybracers"] = 382; +NTIPAliasClassID["xtg"] = 383; NTIPAliasClassID["battlegauntlets"] = 383; +NTIPAliasClassID["xhg"] = 384; NTIPAliasClassID["wargauntlets"] = 384; +NTIPAliasClassID["xlb"] = 385; NTIPAliasClassID["demonhideboots"] = 385; +NTIPAliasClassID["xvb"] = 386; NTIPAliasClassID["sharkskinboots"] = 386; +NTIPAliasClassID["xmb"] = 387; NTIPAliasClassID["meshboots"] = 387; +NTIPAliasClassID["xtb"] = 388; NTIPAliasClassID["battleboots"] = 388; +NTIPAliasClassID["xhb"] = 389; NTIPAliasClassID["warboots"] = 389; +NTIPAliasClassID["zlb"] = 390; NTIPAliasClassID["demonhidesash"] = 390; +NTIPAliasClassID["zvb"] = 391; NTIPAliasClassID["sharkskinbelt"] = 391; +NTIPAliasClassID["zmb"] = 392; NTIPAliasClassID["meshbelt"] = 392; +NTIPAliasClassID["ztb"] = 393; NTIPAliasClassID["battlebelt"] = 393; +NTIPAliasClassID["zhb"] = 394; NTIPAliasClassID["warbelt"] = 394; +NTIPAliasClassID["xh9"] = 395; NTIPAliasClassID["grimhelm"] = 395; +NTIPAliasClassID["xsh"] = 396; NTIPAliasClassID["grimshield"] = 396; +NTIPAliasClassID["xpk"] = 397; NTIPAliasClassID["barbedshield"] = 397; +NTIPAliasClassID["dr1"] = 398; NTIPAliasClassID["wolfhead"] = 398; +NTIPAliasClassID["dr2"] = 399; NTIPAliasClassID["hawkhelm"] = 399; +NTIPAliasClassID["dr3"] = 400; NTIPAliasClassID["antlers"] = 400; +NTIPAliasClassID["dr4"] = 401; NTIPAliasClassID["falconmask"] = 401; +NTIPAliasClassID["dr5"] = 402; NTIPAliasClassID["spiritmask"] = 402; +NTIPAliasClassID["ba1"] = 403; NTIPAliasClassID["jawbonecap"] = 403; +NTIPAliasClassID["ba2"] = 404; NTIPAliasClassID["fangedhelm"] = 404; +NTIPAliasClassID["ba3"] = 405; NTIPAliasClassID["hornedhelm"] = 405; +NTIPAliasClassID["ba4"] = 406; NTIPAliasClassID["assaulthelmet"] = 406; +NTIPAliasClassID["ba5"] = 407; NTIPAliasClassID["avengerguard"] = 407; +NTIPAliasClassID["pa1"] = 408; NTIPAliasClassID["targe"] = 408; +NTIPAliasClassID["pa2"] = 409; NTIPAliasClassID["rondache"] = 409; +NTIPAliasClassID["pa3"] = 410; NTIPAliasClassID["heraldicshield"] = 410; +NTIPAliasClassID["pa4"] = 411; NTIPAliasClassID["aerinshield"] = 411; +NTIPAliasClassID["pa5"] = 412; NTIPAliasClassID["crownshield"] = 412; +NTIPAliasClassID["ne1"] = 413; NTIPAliasClassID["preservedhead"] = 413; +NTIPAliasClassID["ne2"] = 414; NTIPAliasClassID["zombiehead"] = 414; +NTIPAliasClassID["ne3"] = 415; NTIPAliasClassID["unravellerhead"] = 415; +NTIPAliasClassID["ne4"] = 416; NTIPAliasClassID["gargoylehead"] = 416; +NTIPAliasClassID["ne5"] = 417; NTIPAliasClassID["demonhead"] = 417; +NTIPAliasClassID["ci0"] = 418; NTIPAliasClassID["circlet"] = 418; +NTIPAliasClassID["ci1"] = 419; NTIPAliasClassID["coronet"] = 419; +NTIPAliasClassID["ci2"] = 420; NTIPAliasClassID["tiara"] = 420; +NTIPAliasClassID["ci3"] = 421; NTIPAliasClassID["diadem"] = 421; +NTIPAliasClassID["uap"] = 422; NTIPAliasClassID["shako"] = 422; +NTIPAliasClassID["ukp"] = 423; NTIPAliasClassID["hydraskull"] = 423; +NTIPAliasClassID["ulm"] = 424; NTIPAliasClassID["armet"] = 424; +NTIPAliasClassID["uhl"] = 425; NTIPAliasClassID["giantconch"] = 425; +NTIPAliasClassID["uhm"] = 426; NTIPAliasClassID["spiredhelm"] = 426; +NTIPAliasClassID["urn"] = 427; NTIPAliasClassID["corona"] = 427; +NTIPAliasClassID["usk"] = 428; NTIPAliasClassID["demonhead"] = 428; +NTIPAliasClassID["uui"] = 429; NTIPAliasClassID["duskshroud"] = 429; +NTIPAliasClassID["uea"] = 430; NTIPAliasClassID["wyrmhide"] = 430; +NTIPAliasClassID["ula"] = 431; NTIPAliasClassID["scarabhusk"] = 431; +NTIPAliasClassID["utu"] = 432; NTIPAliasClassID["wirefleece"] = 432; +NTIPAliasClassID["ung"] = 433; NTIPAliasClassID["diamondmail"] = 433; +NTIPAliasClassID["ucl"] = 434; NTIPAliasClassID["loricatedmail"] = 434; +NTIPAliasClassID["uhn"] = 435; NTIPAliasClassID["boneweave"] = 435; +NTIPAliasClassID["urs"] = 436; NTIPAliasClassID["greathauberk"] = 436; +NTIPAliasClassID["upl"] = 437; NTIPAliasClassID["balrogskin"] = 437; +NTIPAliasClassID["ult"] = 438; NTIPAliasClassID["hellforgeplate"] = 438; +NTIPAliasClassID["uld"] = 439; NTIPAliasClassID["krakenshell"] = 439; +NTIPAliasClassID["uth"] = 440; NTIPAliasClassID["lacqueredplate"] = 440; +NTIPAliasClassID["uul"] = 441; NTIPAliasClassID["shadowplate"] = 441; +NTIPAliasClassID["uar"] = 442; NTIPAliasClassID["sacredarmor"] = 442; +NTIPAliasClassID["utp"] = 443; NTIPAliasClassID["archonplate"] = 443; +NTIPAliasClassID["uuc"] = 444; NTIPAliasClassID["heater"] = 444; +NTIPAliasClassID["uml"] = 445; NTIPAliasClassID["luna"] = 445; +NTIPAliasClassID["urg"] = 446; NTIPAliasClassID["hyperion"] = 446; +NTIPAliasClassID["uit"] = 447; NTIPAliasClassID["monarch"] = 447; +NTIPAliasClassID["uow"] = 448; NTIPAliasClassID["aegis"] = 448; +NTIPAliasClassID["uts"] = 449; NTIPAliasClassID["ward"] = 449; +NTIPAliasClassID["ulg"] = 450; NTIPAliasClassID["bramblemitts"] = 450; +NTIPAliasClassID["uvg"] = 451; NTIPAliasClassID["vampirebonegloves"] = 451; +NTIPAliasClassID["umg"] = 452; NTIPAliasClassID["vambraces"] = 452; +NTIPAliasClassID["utg"] = 453; NTIPAliasClassID["crusadergauntlets"] = 453; +NTIPAliasClassID["uhg"] = 454; NTIPAliasClassID["ogregauntlets"] = 454; +NTIPAliasClassID["ulb"] = 455; NTIPAliasClassID["wyrmhideboots"] = 455; +NTIPAliasClassID["uvb"] = 456; NTIPAliasClassID["scarabshellboots"] = 456; +NTIPAliasClassID["umb"] = 457; NTIPAliasClassID["boneweaveboots"] = 457; +NTIPAliasClassID["utb"] = 458; NTIPAliasClassID["mirroredboots"] = 458; +NTIPAliasClassID["uhb"] = 459; NTIPAliasClassID["myrmidongreaves"] = 459; +NTIPAliasClassID["ulc"] = 460; NTIPAliasClassID["spiderwebsash"] = 460; +NTIPAliasClassID["uvc"] = 461; NTIPAliasClassID["vampirefangbelt"] = 461; +NTIPAliasClassID["umc"] = 462; NTIPAliasClassID["mithrilcoil"] = 462; +NTIPAliasClassID["utc"] = 463; NTIPAliasClassID["trollbelt"] = 463; +NTIPAliasClassID["uhc"] = 464; NTIPAliasClassID["colossusgirdle"] = 464; +NTIPAliasClassID["uh9"] = 465; NTIPAliasClassID["bonevisage"] = 465; +NTIPAliasClassID["ush"] = 466; NTIPAliasClassID["trollnest"] = 466; +NTIPAliasClassID["upk"] = 467; NTIPAliasClassID["bladebarrier"] = 467; +NTIPAliasClassID["dr6"] = 468; NTIPAliasClassID["alphahelm"] = 468; +NTIPAliasClassID["dr7"] = 469; NTIPAliasClassID["griffonheaddress"] = 469; +NTIPAliasClassID["dr8"] = 470; NTIPAliasClassID["hunter'sguise"] = 470; +NTIPAliasClassID["dr9"] = 471; NTIPAliasClassID["sacredfeathers"] = 471; +NTIPAliasClassID["dra"] = 472; NTIPAliasClassID["totemicmask"] = 472; +NTIPAliasClassID["ba6"] = 473; NTIPAliasClassID["jawbonevisor"] = 473; +NTIPAliasClassID["ba7"] = 474; NTIPAliasClassID["lionhelm"] = 474; +NTIPAliasClassID["ba8"] = 475; NTIPAliasClassID["ragemask"] = 475; +NTIPAliasClassID["ba9"] = 476; NTIPAliasClassID["savagehelmet"] = 476; +NTIPAliasClassID["baa"] = 477; NTIPAliasClassID["slayerguard"] = 477; +NTIPAliasClassID["pa6"] = 478; NTIPAliasClassID["akarantarge"] = 478; +NTIPAliasClassID["pa7"] = 479; NTIPAliasClassID["akaranrondache"] = 479; +NTIPAliasClassID["pa8"] = 480; NTIPAliasClassID["protectorshield"] = 480; +NTIPAliasClassID["pa9"] = 481; NTIPAliasClassID["gildedshield"] = 481; +NTIPAliasClassID["paa"] = 482; NTIPAliasClassID["royalshield"] = 482; +NTIPAliasClassID["ne6"] = 483; NTIPAliasClassID["mummifiedtrophy"] = 483; +NTIPAliasClassID["ne7"] = 484; NTIPAliasClassID["fetishtrophy"] = 484; +NTIPAliasClassID["ne8"] = 485; NTIPAliasClassID["sextontrophy"] = 485; +NTIPAliasClassID["ne9"] = 486; NTIPAliasClassID["cantortrophy"] = 486; +NTIPAliasClassID["nea"] = 487; NTIPAliasClassID["hierophanttrophy"] = 487; +NTIPAliasClassID["drb"] = 488; NTIPAliasClassID["bloodspirit"] = 488; +NTIPAliasClassID["drc"] = 489; NTIPAliasClassID["sunspirit"] = 489; +NTIPAliasClassID["drd"] = 490; NTIPAliasClassID["earthspirit"] = 490; +NTIPAliasClassID["dre"] = 491; NTIPAliasClassID["skyspirit"] = 491; +NTIPAliasClassID["drf"] = 492; NTIPAliasClassID["dreamspirit"] = 492; +NTIPAliasClassID["bab"] = 493; NTIPAliasClassID["carnagehelm"] = 493; +NTIPAliasClassID["bac"] = 494; NTIPAliasClassID["furyvisor"] = 494; +NTIPAliasClassID["bad"] = 495; NTIPAliasClassID["destroyerhelm"] = 495; +NTIPAliasClassID["bae"] = 496; NTIPAliasClassID["conquerorcrown"] = 496; +NTIPAliasClassID["baf"] = 497; NTIPAliasClassID["guardiancrown"] = 497; +NTIPAliasClassID["pab"] = 498; NTIPAliasClassID["sacredtarge"] = 498; +NTIPAliasClassID["pac"] = 499; NTIPAliasClassID["sacredrondache"] = 499; +NTIPAliasClassID["pad"] = 500; NTIPAliasClassID["kurastshield"] = 500; +NTIPAliasClassID["pae"] = 501; NTIPAliasClassID["zakarumshield"] = 501; +NTIPAliasClassID["paf"] = 502; NTIPAliasClassID["vortexshield"] = 502; +NTIPAliasClassID["neb"] = 503; NTIPAliasClassID["minionskull"] = 503; +NTIPAliasClassID["neg"] = 504; NTIPAliasClassID["hellspawnskull"] = 504; +NTIPAliasClassID["ned"] = 505; NTIPAliasClassID["overseerskull"] = 505; +NTIPAliasClassID["nee"] = 506; NTIPAliasClassID["succubusskull"] = 506; +NTIPAliasClassID["nef"] = 507; NTIPAliasClassID["bloodlordskull"] = 507; +NTIPAliasClassID["elx"] = 508; NTIPAliasClassID["elixir"] = 508; +NTIPAliasClassID["hpo"] = 509; +NTIPAliasClassID["mpo"] = 510; +NTIPAliasClassID["hpf"] = 511; +NTIPAliasClassID["mpf"] = 512; +NTIPAliasClassID["vps"] = 513; NTIPAliasClassID["staminapotion"] = 513; +NTIPAliasClassID["yps"] = 514; NTIPAliasClassID["antidotepotion"] = 514; +NTIPAliasClassID["rvs"] = 515; NTIPAliasClassID["rejuvenationpotion"] = 515; +NTIPAliasClassID["rvl"] = 516; NTIPAliasClassID["fullrejuvenationpotion"] = 516; +NTIPAliasClassID["wms"] = 517; NTIPAliasClassID["thawingpotion"] = 517; +NTIPAliasClassID["tbk"] = 518; NTIPAliasClassID["tomeoftownportal"] = 518; +NTIPAliasClassID["ibk"] = 519; NTIPAliasClassID["tomeofidentify"] = 519; +NTIPAliasClassID["amu"] = 520; NTIPAliasClassID["amulet"] = 520; +NTIPAliasClassID["vip"] = 521; NTIPAliasClassID["topofthehoradricstaff"] = 521; +NTIPAliasClassID["rin"] = 522; NTIPAliasClassID["ring"] = 522; +NTIPAliasClassID["gld"] = 523; NTIPAliasClassID["gold"] = 523; +NTIPAliasClassID["bks"] = 524; NTIPAliasClassID["scrollofinifuss"] = 524; +NTIPAliasClassID["bkd"] = 525; NTIPAliasClassID["keytothecairnstones"] = 525; +NTIPAliasClassID["aqv"] = 526; NTIPAliasClassID["arrows"] = 526; +NTIPAliasClassID["tch"] = 527; NTIPAliasClassID["torch"] = 527; +NTIPAliasClassID["cqv"] = 528; NTIPAliasClassID["bolts"] = 528; +NTIPAliasClassID["tsc"] = 529; NTIPAliasClassID["scrolloftownportal"] = 529; +NTIPAliasClassID["isc"] = 530; NTIPAliasClassID["scrollofidentify"] = 530; +NTIPAliasClassID["hrt"] = 531; NTIPAliasClassID["heart"] = 531; +NTIPAliasClassID["brz"] = 532; NTIPAliasClassID["brain"] = 532; +NTIPAliasClassID["jaw"] = 533; NTIPAliasClassID["jawbone"] = 533; +NTIPAliasClassID["eyz"] = 534; NTIPAliasClassID["eye"] = 534; +NTIPAliasClassID["hrn"] = 535; NTIPAliasClassID["horn"] = 535; +NTIPAliasClassID["tal"] = 536; NTIPAliasClassID["tail"] = 536; +NTIPAliasClassID["flg"] = 537; NTIPAliasClassID["flag"] = 537; +NTIPAliasClassID["fng"] = 538; NTIPAliasClassID["fang"] = 538; +NTIPAliasClassID["qll"] = 539; NTIPAliasClassID["quill"] = 539; +NTIPAliasClassID["sol"] = 540; NTIPAliasClassID["soul"] = 540; +NTIPAliasClassID["scz"] = 541; NTIPAliasClassID["scalp"] = 541; +NTIPAliasClassID["spe"] = 542; NTIPAliasClassID["spleen"] = 542; +NTIPAliasClassID["key"] = 543; +NTIPAliasClassID["luv"] = 544; NTIPAliasClassID["theblacktowerkey"] = 544; +NTIPAliasClassID["xyz"] = 545; NTIPAliasClassID["potionoflife"] = 545; +NTIPAliasClassID["j34"] = 546; NTIPAliasClassID["ajadefigurine"] = 546; +NTIPAliasClassID["g34"] = 547; NTIPAliasClassID["thegoldenbird"] = 547; +NTIPAliasClassID["bbb"] = 548; NTIPAliasClassID["lamesen'stome"] = 548; +NTIPAliasClassID["box"] = 549; NTIPAliasClassID["horadriccube"] = 549; +NTIPAliasClassID["tr1"] = 550; NTIPAliasClassID["horadricscroll"] = 550; +NTIPAliasClassID["mss"] = 551; NTIPAliasClassID["mephisto'ssoulstone"] = 551; +NTIPAliasClassID["ass"] = 552; NTIPAliasClassID["bookofskill"] = 552; +NTIPAliasClassID["qey"] = 553; NTIPAliasClassID["khalim'seye"] = 553; +NTIPAliasClassID["qhr"] = 554; NTIPAliasClassID["khalim'sheart"] = 554; +NTIPAliasClassID["qbr"] = 555; NTIPAliasClassID["khalim'sbrain"] = 555; +NTIPAliasClassID["ear"] = 556; +NTIPAliasClassID["gcv"] = 557; NTIPAliasClassID["chippedamethyst"] = 557; +NTIPAliasClassID["gfv"] = 558; NTIPAliasClassID["flawedamethyst"] = 558; +NTIPAliasClassID["gsv"] = 559; NTIPAliasClassID["amethyst"] = 559; +NTIPAliasClassID["gzv"] = 560; NTIPAliasClassID["flawlessamethyst"] = 560; +NTIPAliasClassID["gpv"] = 561; NTIPAliasClassID["perfectamethyst"] = 561; +NTIPAliasClassID["gcy"] = 562; NTIPAliasClassID["chippedtopaz"] = 562; +NTIPAliasClassID["gfy"] = 563; NTIPAliasClassID["flawedtopaz"] = 563; +NTIPAliasClassID["gsy"] = 564; NTIPAliasClassID["topaz"] = 564; +NTIPAliasClassID["gly"] = 565; NTIPAliasClassID["flawlesstopaz"] = 565; +NTIPAliasClassID["gpy"] = 566; NTIPAliasClassID["perfecttopaz"] = 566; +NTIPAliasClassID["gcb"] = 567; NTIPAliasClassID["chippedsapphire"] = 567; +NTIPAliasClassID["gfb"] = 568; NTIPAliasClassID["flawedsapphire"] = 568; +NTIPAliasClassID["gsb"] = 569; NTIPAliasClassID["sapphire"] = 569; +NTIPAliasClassID["glb"] = 570; NTIPAliasClassID["flawlesssapphire"] = 570; +NTIPAliasClassID["gpb"] = 571; NTIPAliasClassID["perfectsapphire"] = 571; +NTIPAliasClassID["gcg"] = 572; NTIPAliasClassID["chippedemerald"] = 572; +NTIPAliasClassID["gfg"] = 573; NTIPAliasClassID["flawedemerald"] = 573; +NTIPAliasClassID["gsg"] = 574; NTIPAliasClassID["emerald"] = 574; +NTIPAliasClassID["glg"] = 575; NTIPAliasClassID["flawlessemerald"] = 575; +NTIPAliasClassID["gpg"] = 576; NTIPAliasClassID["perfectemerald"] = 576; +NTIPAliasClassID["gcr"] = 577; NTIPAliasClassID["chippedruby"] = 577; +NTIPAliasClassID["gfr"] = 578; NTIPAliasClassID["flawedruby"] = 578; +NTIPAliasClassID["gsr"] = 579; NTIPAliasClassID["ruby"] = 579; +NTIPAliasClassID["glr"] = 580; NTIPAliasClassID["flawlessruby"] = 580; +NTIPAliasClassID["gpr"] = 581; NTIPAliasClassID["perfectruby"] = 581; +NTIPAliasClassID["gcw"] = 582; NTIPAliasClassID["chippeddiamond"] = 582; +NTIPAliasClassID["gfw"] = 583; NTIPAliasClassID["flaweddiamond"] = 583; +NTIPAliasClassID["gsw"] = 584; NTIPAliasClassID["diamond"] = 584; +NTIPAliasClassID["glw"] = 585; NTIPAliasClassID["flawlessdiamond"] = 585; +NTIPAliasClassID["gpw"] = 586; NTIPAliasClassID["perfectdiamond"] = 586; +NTIPAliasClassID["hp1"] = 587; NTIPAliasClassID["minorhealingpotion"] = 587; +NTIPAliasClassID["hp2"] = 588; NTIPAliasClassID["lighthealingpotion"] = 588; +NTIPAliasClassID["hp3"] = 589; NTIPAliasClassID["healingpotion"] = 589; +NTIPAliasClassID["hp4"] = 590; NTIPAliasClassID["greaterhealingpotion"] = 590; +NTIPAliasClassID["hp5"] = 591; NTIPAliasClassID["superhealingpotion"] = 591; +NTIPAliasClassID["mp1"] = 592; NTIPAliasClassID["minormanapotion"] = 592; +NTIPAliasClassID["mp2"] = 593; NTIPAliasClassID["lightmanapotion"] = 593; +NTIPAliasClassID["mp3"] = 594; NTIPAliasClassID["manapotion"] = 594; +NTIPAliasClassID["mp4"] = 595; NTIPAliasClassID["greatermanapotion"] = 595; +NTIPAliasClassID["mp5"] = 596; NTIPAliasClassID["supermanapotion"] = 596; +NTIPAliasClassID["skc"] = 597; NTIPAliasClassID["chippedskull"] = 597; +NTIPAliasClassID["skf"] = 598; NTIPAliasClassID["flawedskull"] = 598; +NTIPAliasClassID["sku"] = 599; NTIPAliasClassID["skull"] = 599; +NTIPAliasClassID["skl"] = 600; NTIPAliasClassID["flawlessskull"] = 600; +NTIPAliasClassID["skz"] = 601; NTIPAliasClassID["perfectskull"] = 601; +NTIPAliasClassID["hrb"] = 602; NTIPAliasClassID["herb"] = 602; +NTIPAliasClassID["cm1"] = 603; NTIPAliasClassID["smallcharm"] = 603; +NTIPAliasClassID["cm2"] = 604; NTIPAliasClassID["largecharm"] = 604; +NTIPAliasClassID["cm3"] = 605; NTIPAliasClassID["grandcharm"] = 605; +NTIPAliasClassID["rps"] = 606; +NTIPAliasClassID["rpl"] = 607; +NTIPAliasClassID["bps"] = 608; +NTIPAliasClassID["bpl"] = 609; +NTIPAliasClassID["r01"] = 610; NTIPAliasClassID["elrune"] = 610; +NTIPAliasClassID["r02"] = 611; NTIPAliasClassID["eldrune"] = 611; +NTIPAliasClassID["r03"] = 612; NTIPAliasClassID["tirrune"] = 612; +NTIPAliasClassID["r04"] = 613; NTIPAliasClassID["nefrune"] = 613; +NTIPAliasClassID["r05"] = 614; NTIPAliasClassID["ethrune"] = 614; +NTIPAliasClassID["r06"] = 615; NTIPAliasClassID["ithrune"] = 615; +NTIPAliasClassID["r07"] = 616; NTIPAliasClassID["talrune"] = 616; +NTIPAliasClassID["r08"] = 617; NTIPAliasClassID["ralrune"] = 617; +NTIPAliasClassID["r09"] = 618; NTIPAliasClassID["ortrune"] = 618; +NTIPAliasClassID["r10"] = 619; NTIPAliasClassID["thulrune"] = 619; +NTIPAliasClassID["r11"] = 620; NTIPAliasClassID["amnrune"] = 620; +NTIPAliasClassID["r12"] = 621; NTIPAliasClassID["solrune"] = 621; +NTIPAliasClassID["r13"] = 622; NTIPAliasClassID["shaelrune"] = 622; +NTIPAliasClassID["r14"] = 623; NTIPAliasClassID["dolrune"] = 623; +NTIPAliasClassID["r15"] = 624; NTIPAliasClassID["helrune"] = 624; +NTIPAliasClassID["r16"] = 625; NTIPAliasClassID["iorune"] = 625; +NTIPAliasClassID["r17"] = 626; NTIPAliasClassID["lumrune"] = 626; +NTIPAliasClassID["r18"] = 627; NTIPAliasClassID["korune"] = 627; +NTIPAliasClassID["r19"] = 628; NTIPAliasClassID["falrune"] = 628; +NTIPAliasClassID["r20"] = 629; NTIPAliasClassID["lemrune"] = 629; +NTIPAliasClassID["r21"] = 630; NTIPAliasClassID["pulrune"] = 630; +NTIPAliasClassID["r22"] = 631; NTIPAliasClassID["umrune"] = 631; +NTIPAliasClassID["r23"] = 632; NTIPAliasClassID["malrune"] = 632; +NTIPAliasClassID["r24"] = 633; NTIPAliasClassID["istrune"] = 633; +NTIPAliasClassID["r25"] = 634; NTIPAliasClassID["gulrune"] = 634; +NTIPAliasClassID["r26"] = 635; NTIPAliasClassID["vexrune"] = 635; +NTIPAliasClassID["r27"] = 636; NTIPAliasClassID["ohmrune"] = 636; +NTIPAliasClassID["r28"] = 637; NTIPAliasClassID["lorune"] = 637; +NTIPAliasClassID["r29"] = 638; NTIPAliasClassID["surrune"] = 638; +NTIPAliasClassID["r30"] = 639; NTIPAliasClassID["berrune"] = 639; +NTIPAliasClassID["r31"] = 640; NTIPAliasClassID["jahrune"] = 640; +NTIPAliasClassID["r32"] = 641; NTIPAliasClassID["chamrune"] = 641; +NTIPAliasClassID["r33"] = 642; NTIPAliasClassID["zodrune"] = 642; +NTIPAliasClassID["jew"] = 643; NTIPAliasClassID["jewel"] = 643; +NTIPAliasClassID["ice"] = 644; NTIPAliasClassID["malah'spotion"] = 644; +NTIPAliasClassID["0sc"] = 645; NTIPAliasClassID["scrollofknowledge"] = 645; +NTIPAliasClassID["tr2"] = 646; NTIPAliasClassID["scrollofresistance"] = 646; +NTIPAliasClassID["pk1"] = 647; NTIPAliasClassID["keyofterror"] = 647; +NTIPAliasClassID["pk2"] = 648; NTIPAliasClassID["keyofhate"] = 648; +NTIPAliasClassID["pk3"] = 649; NTIPAliasClassID["keyofdestruction"] = 649; +NTIPAliasClassID["dhn"] = 650; NTIPAliasClassID["diablo'shorn"] = 650; +NTIPAliasClassID["bey"] = 651; NTIPAliasClassID["baal'seye"] = 651; +NTIPAliasClassID["mbr"] = 652; NTIPAliasClassID["mephisto'sbrain"] = 652; +NTIPAliasClassID["toa"] = 653; NTIPAliasClassID["tokenofabsolution"] = 653; +NTIPAliasClassID["tes"] = 654; NTIPAliasClassID["twistedessenceofsuffering"] = 654; +NTIPAliasClassID["ceh"] = 655; NTIPAliasClassID["chargedessenceofhatred"] = 655; +NTIPAliasClassID["bet"] = 656; NTIPAliasClassID["burningessenceofterror"] = 656; +NTIPAliasClassID["fed"] = 657; NTIPAliasClassID["festeringessenceofdestruction"] = 657; +NTIPAliasClassID["std"] = 658; NTIPAliasClassID["standardofheroes"] = 658; -var _NTIPAliasClass = new Array(); -_NTIPAliasClass["normal"]=0; -_NTIPAliasClass["exceptional"]=1; -_NTIPAliasClass["elite"]=2; +var NTIPAliasClass = {}; +NTIPAliasClass["normal"] = 0; +NTIPAliasClass["exceptional"] = 1; +NTIPAliasClass["elite"] = 2; -var _NTIPAliasQuality = new Array(); -_NTIPAliasQuality["lowquality"]=1; -_NTIPAliasQuality["normal"]=2; -_NTIPAliasQuality["superior"]=3; -_NTIPAliasQuality["magic"]=4; -_NTIPAliasQuality["set"]=5; -_NTIPAliasQuality["rare"]=6; -_NTIPAliasQuality["unique"]=7; -_NTIPAliasQuality["crafted"]=8; +var NTIPAliasQuality = {}; +NTIPAliasQuality["lowquality"] = 1; +NTIPAliasQuality["normal"] = 2; +NTIPAliasQuality["superior"] = 3; +NTIPAliasQuality["magic"] = 4; +NTIPAliasQuality["set"] = 5; +NTIPAliasQuality["rare"] = 6; +NTIPAliasQuality["unique"] = 7; +NTIPAliasQuality["crafted"] = 8; -var _NTIPAliasFlag = new Array(); -_NTIPAliasFlag["identified"]=0x10; -_NTIPAliasFlag["eth"]=0x400000; _NTIPAliasFlag["ethereal"]=0x400000; -_NTIPAliasFlag["runeword"]=0x4000000; +var NTIPAliasFlag = {}; +NTIPAliasFlag["identified"] = 0x10; +NTIPAliasFlag["eth"] = 0x400000; NTIPAliasFlag["ethereal"] = 0x400000; +NTIPAliasFlag["runeword"] = 0x4000000; -var _NTIPAliasStat = new Array(); -_NTIPAliasStat["strength"]=0; -_NTIPAliasStat["energy"]=1; -_NTIPAliasStat["dexterity"]=2; -_NTIPAliasStat["vitality"]=3; -_NTIPAliasStat["statpts"]=4; -_NTIPAliasStat["newskills"]=5; -_NTIPAliasStat["hitpoints"]=6; -_NTIPAliasStat["maxhp"]=7; -_NTIPAliasStat["mana"]=8; -_NTIPAliasStat["maxmana"]=9; -_NTIPAliasStat["stamina"]=10; -_NTIPAliasStat["maxstamina"]=11; -_NTIPAliasStat["level"]=12; -_NTIPAliasStat["experience"]=13; -_NTIPAliasStat["gold"]=14; -_NTIPAliasStat["goldbank"]=15; -_NTIPAliasStat["itemarmorpercent"]=[16,0]; _NTIPAliasStat["enhanceddefense"]=[16,0]; -_NTIPAliasStat["itemmaxdamagepercent"]=[17,0]; -_NTIPAliasStat["itemmindamagepercent"]=[18,0]; _NTIPAliasStat["enhanceddamage"]=[18,0]; -_NTIPAliasStat["tohit"]=19; -_NTIPAliasStat["toblock"]=20; -_NTIPAliasStat["mindamage"]=21; -_NTIPAliasStat["maxdamage"]=22; -_NTIPAliasStat["secondarymindamage"]=23; -_NTIPAliasStat["secondarymaxdamage"]=24; -_NTIPAliasStat["damagepercent"]=25; -_NTIPAliasStat["manarecovery"]=26; -_NTIPAliasStat["manarecoverybonus"]=27; -_NTIPAliasStat["staminarecoverybonus"]=28; -_NTIPAliasStat["lastexp"]=29; -_NTIPAliasStat["nextexp"]=30; +// 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; -_NTIPAliasStat["armorclass"]=31; _NTIPAliasStat["defense"]=31; -_NTIPAliasStat["plusdefense"]=[31,0]; +var NTIPAliasStat = {}; +NTIPAliasStat["strength"] = 0; +NTIPAliasStat["energy"] = 1; +NTIPAliasStat["dexterity"] = 2; +NTIPAliasStat["vitality"] = 3; +NTIPAliasStat["statpts"] = 4; +NTIPAliasStat["newskills"] = 5; +NTIPAliasStat["hitpoints"] = 6; +NTIPAliasStat["maxhp"] = 7; +NTIPAliasStat["mana"] = 8; +NTIPAliasStat["maxmana"] = 9; +NTIPAliasStat["stamina"] = 10; +NTIPAliasStat["maxstamina"] = 11; +NTIPAliasStat["level"] = 12; +NTIPAliasStat["experience"] = 13; +NTIPAliasStat["gold"] = 14; +NTIPAliasStat["goldbank"] = 15; +NTIPAliasStat["itemarmorpercent"] = [16,0]; NTIPAliasStat["enhanceddefense"] = [16,0]; +NTIPAliasStat["itemmaxdamagepercent"] = [17,0]; +NTIPAliasStat["itemmindamagepercent"] = [18,0]; NTIPAliasStat["enhanceddamage"] = [18,0]; +NTIPAliasStat["tohit"] = 19; +NTIPAliasStat["toblock"] = 20; +NTIPAliasStat["plusmindamage"] = [21, 1]; +NTIPAliasStat["mindamage"] = 21; +NTIPAliasStat["plusmaxdamage"] = [22, 1]; +NTIPAliasStat["maxdamage"] = 22; +NTIPAliasStat["secondarymindamage"] = 23; +NTIPAliasStat["secondarymaxdamage"] = 24; +NTIPAliasStat["damagepercent"] = 25; +NTIPAliasStat["manarecovery"] = 26; +NTIPAliasStat["manarecoverybonus"] = 27; +NTIPAliasStat["staminarecoverybonus"] = 28; +NTIPAliasStat["lastexp"] = 29; +NTIPAliasStat["nextexp"] = 30; -_NTIPAliasStat["armorclassvsmissile"]=32; -_NTIPAliasStat["armorclassvshth"]=33; -_NTIPAliasStat["normaldamagereduction"]=34; -_NTIPAliasStat["magicdamagereduction"]=35; -_NTIPAliasStat["damageresist"]=36; -_NTIPAliasStat["magicresist"]=37; -_NTIPAliasStat["maxmagicresist"]=38; -_NTIPAliasStat["fireresist"]=39; -_NTIPAliasStat["maxfireresist"]=40; -_NTIPAliasStat["lightresist"]=41; -_NTIPAliasStat["maxlightresist"]=42; -_NTIPAliasStat["coldresist"]=43; -_NTIPAliasStat["maxcoldresist"]=44; -_NTIPAliasStat["poisonresist"]=45; -_NTIPAliasStat["maxpoisonresist"]=46; -_NTIPAliasStat["damageaura"]=47; -_NTIPAliasStat["firemindam"]=48; -_NTIPAliasStat["firemaxdam"]=49; -_NTIPAliasStat["lightmindam"]=50; -_NTIPAliasStat["lightmaxdam"]=51; -_NTIPAliasStat["magicmindam"]=52; -_NTIPAliasStat["magicmaxdam"]=53; -_NTIPAliasStat["coldmindam"]=54; -_NTIPAliasStat["coldmaxdam"]=55; -_NTIPAliasStat["coldlength"]=56; -_NTIPAliasStat["poisonmindam"]=57; -_NTIPAliasStat["poisonmaxdam"]=58; -_NTIPAliasStat["poisonlength"]=59; -_NTIPAliasStat["lifedrainmindam"]=60; _NTIPAliasStat["lifeleech"]=60; -_NTIPAliasStat["lifedrainmaxdam"]=61; -_NTIPAliasStat["manadrainmindam"]=62; _NTIPAliasStat["manaleech"]=62; -_NTIPAliasStat["manadrainmaxdam"]=63; -_NTIPAliasStat["stamdrainmindam"]=64; -_NTIPAliasStat["stamdrainmaxdam"]=65; -_NTIPAliasStat["stunlength"]=66; -_NTIPAliasStat["velocitypercent"]=67; -_NTIPAliasStat["attackrate"]=68; -_NTIPAliasStat["otheranimrate"]=69; -_NTIPAliasStat["quantity"]=70; -_NTIPAliasStat["value"]=71; -_NTIPAliasStat["durability"]=72; -_NTIPAliasStat["maxdurability"]=73; -_NTIPAliasStat["hpregen"]=74; -_NTIPAliasStat["itemmaxdurabilitypercent"]=75; -_NTIPAliasStat["itemmaxhppercent"]=76; -_NTIPAliasStat["itemmaxmanapercent"]=77; -_NTIPAliasStat["itemattackertakesdamage"]=78; -_NTIPAliasStat["itemgoldbonus"]=79; -_NTIPAliasStat["itemmagicbonus"]=80; -_NTIPAliasStat["itemknockback"]=81; -_NTIPAliasStat["itemtimeduration"]=82; +NTIPAliasStat["armorclass"] = 31; NTIPAliasStat["defense"] = 31; +NTIPAliasStat["plusdefense"] = [31,0]; -_NTIPAliasStat["itemaddclassskills"]=83; -_NTIPAliasStat["itemaddamazonskills"]=[83,0]; _NTIPAliasStat["amazonskills"]=[83,0]; -_NTIPAliasStat["itemaddsorceressskills"]=[83,1]; _NTIPAliasStat["sorceressskills"]=[83,1]; -_NTIPAliasStat["itemaddnecromancerskills"]=[83,2]; _NTIPAliasStat["necromancerskills"]=[83,2]; -_NTIPAliasStat["itemaddpaladinskills"]=[83,3]; _NTIPAliasStat["paladinskills"]=[83,3]; -_NTIPAliasStat["itemaddbarbarianskills"]=[83,4]; _NTIPAliasStat["barbarianskills"]=[83,4]; -_NTIPAliasStat["itemadddruidskills"]=[83,5]; _NTIPAliasStat["druidskills"]=[83,5]; -_NTIPAliasStat["itemaddassassinskills"]=[83,6]; _NTIPAliasStat["assassinskills"]=[83,6]; +NTIPAliasStat["armorclassvsmissile"] = 32; +NTIPAliasStat["armorclassvshth"] = 33; +NTIPAliasStat["normaldamagereduction"] = 34; +NTIPAliasStat["magicdamagereduction"] = 35; +NTIPAliasStat["damageresist"] = 36; +NTIPAliasStat["magicresist"] = 37; +NTIPAliasStat["maxmagicresist"] = 38; +NTIPAliasStat["fireresist"] = 39; +NTIPAliasStat["maxfireresist"] = 40; +NTIPAliasStat["lightresist"] = 41; +NTIPAliasStat["maxlightresist"] = 42; +NTIPAliasStat["coldresist"] = 43; +NTIPAliasStat["maxcoldresist"] = 44; +NTIPAliasStat["poisonresist"] = 45; +NTIPAliasStat["maxpoisonresist"] = 46; +NTIPAliasStat["damageaura"] = 47; +NTIPAliasStat["firemindam"] = 48; +NTIPAliasStat["firemaxdam"] = 49; +NTIPAliasStat["lightmindam"] = 50; +NTIPAliasStat["lightmaxdam"] = 51; +NTIPAliasStat["magicmindam"] = 52; +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; +NTIPAliasStat["lifedrainmindam"] = 60; NTIPAliasStat["lifeleech"] = 60; +NTIPAliasStat["lifedrainmaxdam"] = 61; +NTIPAliasStat["manadrainmindam"] = 62; NTIPAliasStat["manaleech"] = 62; +NTIPAliasStat["manadrainmaxdam"] = 63; +NTIPAliasStat["stamdrainmindam"] = 64; +NTIPAliasStat["stamdrainmaxdam"] = 65; +NTIPAliasStat["stunlength"] = 66; +NTIPAliasStat["velocitypercent"] = 67; +NTIPAliasStat["attackrate"] = 68; +NTIPAliasStat["otheranimrate"] = 69; +NTIPAliasStat["quantity"] = 70; +NTIPAliasStat["value"] = 71; +NTIPAliasStat["durability"] = 72; +NTIPAliasStat["maxdurability"] = 73; +NTIPAliasStat["hpregen"] = 74; +NTIPAliasStat["itemmaxdurabilitypercent"] = 75; +NTIPAliasStat["itemmaxhppercent"] = 76; +NTIPAliasStat["itemmaxmanapercent"] = 77; +NTIPAliasStat["itemattackertakesdamage"] = 78; +NTIPAliasStat["itemgoldbonus"] = 79; +NTIPAliasStat["itemmagicbonus"] = 80; +NTIPAliasStat["itemknockback"] = 81; +NTIPAliasStat["itemtimeduration"] = 82; -_NTIPAliasStat["unsentparam1"]=84; -_NTIPAliasStat["itemaddexperience"]=85; -_NTIPAliasStat["itemhealafterkill"]=86; -_NTIPAliasStat["itemreducedprices"]=87; -_NTIPAliasStat["itemdoubleherbduration"]=88; -_NTIPAliasStat["itemlightradius"]=89; -_NTIPAliasStat["itemlightcolor"]=90; -_NTIPAliasStat["itemreqpercent"]=91; -_NTIPAliasStat["itemlevelreq"]=92; -_NTIPAliasStat["itemfasterattackrate"]=93; _NTIPAliasStat["ias"]=93; -_NTIPAliasStat["itemlevelreqpct"]=94; -_NTIPAliasStat["lastblockframe"]=95; -_NTIPAliasStat["itemfastermovevelocity"]=96; _NTIPAliasStat["frw"]=96; +NTIPAliasStat["itemaddclassskills"] = 83; +NTIPAliasStat["itemaddamazonskills"] = [83,0]; NTIPAliasStat["amazonskills"] = [83,0]; +NTIPAliasStat["itemaddsorceressskills"] = [83,1]; NTIPAliasStat["sorceressskills"] = [83,1]; +NTIPAliasStat["itemaddnecromancerskills"] = [83,2]; NTIPAliasStat["necromancerskills"] = [83,2]; +NTIPAliasStat["itemaddpaladinskills"] = [83,3]; NTIPAliasStat["paladinskills"] = [83,3]; +NTIPAliasStat["itemaddbarbarianskills"] = [83,4]; NTIPAliasStat["barbarianskills"] = [83,4]; +NTIPAliasStat["itemadddruidskills"] = [83,5]; NTIPAliasStat["druidskills"] = [83,5]; +NTIPAliasStat["itemaddassassinskills"] = [83,6]; NTIPAliasStat["assassinskills"] = [83,6]; + +NTIPAliasStat["unsentparam1"] = 84; +NTIPAliasStat["itemaddexperience"] = 85; +NTIPAliasStat["itemhealafterkill"] = 86; +NTIPAliasStat["itemreducedprices"] = 87; +NTIPAliasStat["itemdoubleherbduration"] = 88; +NTIPAliasStat["itemlightradius"] = 89; +NTIPAliasStat["itemlightcolor"] = 90; +NTIPAliasStat["itemreqpercent"] = 91; +NTIPAliasStat["itemlevelreq"] = 92; +NTIPAliasStat["itemfasterattackrate"] = 93; NTIPAliasStat["ias"] = 93; +NTIPAliasStat["itemlevelreqpct"] = 94; +NTIPAliasStat["lastblockframe"] = 95; +NTIPAliasStat["itemfastermovevelocity"] = 96; NTIPAliasStat["frw"] = 96; // oskill -_NTIPAliasStat["itemnonclassskill"]=97; +NTIPAliasStat["itemnonclassskill"] = 97; // Amazon -_NTIPAliasStat["plusskillguidedarrow"]=[97,22]; +NTIPAliasStat["plusskillcriticalstrike"] = [97,9]; +NTIPAliasStat["plusskillguidedarrow"] = [97,22]; // Sorceress -_NTIPAliasStat["plusskillteleport"]=[97,54]; +NTIPAliasStat["plusskillteleport"] = [97,54]; // Barbarian -_NTIPAliasStat["plusskillbattleorders"]=[97,149]; -_NTIPAliasStat["plusskillbattlecommand"]=[97,155]; -_NTIPAliasStat["plusskillbattlecry"]=[97,146]; +NTIPAliasStat["plusskillbattleorders"] = [97,149]; +NTIPAliasStat["plusskillbattlecommand"] = [97,155]; +NTIPAliasStat["plusskillbattlecry"] = [97,146]; // Druid -_NTIPAliasStat["plusskillwerewolf"]=[97,223]; -_NTIPAliasStat["plusskillshapeshifting"]=[97,224]; _NTIPAliasStat["plusskilllycanthropy"]=[97,224]; -_NTIPAliasStat["plusskillsummonspiritwolf"]=[97,227]; +NTIPAliasStat["plusskillwerewolf"] = [97,223]; +NTIPAliasStat["plusskillshapeshifting"] = [97,224]; NTIPAliasStat["plusskilllycanthropy"] = [97,224]; +NTIPAliasStat["plusskillsummonspiritwolf"] = [97,227]; -_NTIPAliasStat["state"]=98; -_NTIPAliasStat["itemfastergethitrate"]=99; _NTIPAliasStat["fhr"]=99; -_NTIPAliasStat["monsterplayercount"]=100; -_NTIPAliasStat["skillpoisonoverridelength"]=101; -_NTIPAliasStat["itemfasterblockrate"]=102; _NTIPAliasStat["fbr"]=102; -_NTIPAliasStat["skillbypassundead"]=103; -_NTIPAliasStat["skillbypassdemons"]=104; -_NTIPAliasStat["itemfastercastrate"]=105; _NTIPAliasStat["fcr"]=105; -_NTIPAliasStat["skillbypassbeasts"]=106; +NTIPAliasStat["state"] = 98; +NTIPAliasStat["itemfastergethitrate"] = 99; NTIPAliasStat["fhr"] = 99; +NTIPAliasStat["monsterplayercount"] = 100; +NTIPAliasStat["skillpoisonoverridelength"] = 101; +NTIPAliasStat["itemfasterblockrate"] = 102; NTIPAliasStat["fbr"] = 102; +NTIPAliasStat["skillbypassundead"] = 103; +NTIPAliasStat["skillbypassdemons"] = 104; +NTIPAliasStat["itemfastercastrate"] = 105; NTIPAliasStat["fcr"] = 105; +NTIPAliasStat["skillbypassbeasts"] = 106; -_NTIPAliasStat["itemsingleskill"]=107; +NTIPAliasStat["itemsingleskill"] = 107; // Amazon skills -_NTIPAliasStat["skillmagicarrow"]=[107,6]; -_NTIPAliasStat["skillfirearrow"]=[107,7]; -_NTIPAliasStat["skillinnersight"]=[107,8]; -_NTIPAliasStat["skillcriticalstrike"]=[107,9]; -_NTIPAliasStat["skilljab"]=[107,10]; -_NTIPAliasStat["skillcoldarrow"]=[107,11]; -_NTIPAliasStat["skillmultipleshot"]=[107,12]; -_NTIPAliasStat["skilldodge"]=[107,13]; -_NTIPAliasStat["skillpowerstrike"]=[107,14]; -_NTIPAliasStat["skillpoisonjavelin"]=[107,15]; -_NTIPAliasStat["skillexplodingarrow"]=[107,16]; -_NTIPAliasStat["skillslowmissiles"]=[107,17]; -_NTIPAliasStat["skillavoid"]=[107,18]; -_NTIPAliasStat["skillimpale"]=[107,19]; -_NTIPAliasStat["skilllightningbolt"]=[107,20]; -_NTIPAliasStat["skillicearrow"]=[107,21]; -_NTIPAliasStat["skillguidedarrow"]=[107,22]; -_NTIPAliasStat["skillpenetrate"]=[107,23]; -_NTIPAliasStat["skillchargedstrike"]=[107,24]; -_NTIPAliasStat["skillplaguejavelin"]=[107,25]; -_NTIPAliasStat["skillstrafe"]=[107,26]; -_NTIPAliasStat["skillimmolationarrow"]=[107,27]; -_NTIPAliasStat["skilldecoy"]=[107,28]; -_NTIPAliasStat["skillevade"]=[107,29]; -_NTIPAliasStat["skillfend"]=[107,30]; -_NTIPAliasStat["skillfreezingarrow"]=[107,31]; -_NTIPAliasStat["skillvalkyrie"]=[107,32]; -_NTIPAliasStat["skillpierce"]=[107,33]; -_NTIPAliasStat["skilllightningstrike"]=[107,34]; -_NTIPAliasStat["skilllightningfury"]=[107,35]; +NTIPAliasStat["skillmagicarrow"] = [107,6]; +NTIPAliasStat["skillfirearrow"] = [107,7]; +NTIPAliasStat["skillinnersight"] = [107,8]; +NTIPAliasStat["skillcriticalstrike"] = [107,9]; +NTIPAliasStat["skilljab"] = [107,10]; +NTIPAliasStat["skillcoldarrow"] = [107,11]; +NTIPAliasStat["skillmultipleshot"] = [107,12]; +NTIPAliasStat["skilldodge"] = [107,13]; +NTIPAliasStat["skillpowerstrike"] = [107,14]; +NTIPAliasStat["skillpoisonjavelin"] = [107,15]; +NTIPAliasStat["skillexplodingarrow"] = [107,16]; +NTIPAliasStat["skillslowmissiles"] = [107,17]; +NTIPAliasStat["skillavoid"] = [107,18]; +NTIPAliasStat["skillimpale"] = [107,19]; +NTIPAliasStat["skilllightningbolt"] = [107,20]; +NTIPAliasStat["skillicearrow"] = [107,21]; +NTIPAliasStat["skillguidedarrow"] = [107,22]; +NTIPAliasStat["skillpenetrate"] = [107,23]; +NTIPAliasStat["skillchargedstrike"] = [107,24]; +NTIPAliasStat["skillplaguejavelin"] = [107,25]; +NTIPAliasStat["skillstrafe"] = [107,26]; +NTIPAliasStat["skillimmolationarrow"] = [107,27]; +NTIPAliasStat["skilldecoy"] = [107,28]; +NTIPAliasStat["skillevade"] = [107,29]; +NTIPAliasStat["skillfend"] = [107,30]; +NTIPAliasStat["skillfreezingarrow"] = [107,31]; +NTIPAliasStat["skillvalkyrie"] = [107,32]; +NTIPAliasStat["skillpierce"] = [107,33]; +NTIPAliasStat["skilllightningstrike"] = [107,34]; +NTIPAliasStat["skilllightningfury"] = [107,35]; // Sorceress skills -_NTIPAliasStat["skillfirebolt"]=[107,36]; -_NTIPAliasStat["skillwarmth"]=[107,37]; -_NTIPAliasStat["skillchargedbolt"]=[107,38]; -_NTIPAliasStat["skillicebolt"]=[107,39]; -_NTIPAliasStat["skillfrozenarmor"]=[107,40]; -_NTIPAliasStat["skillinferno"]=[107,41]; -_NTIPAliasStat["skillstaticfield"]=[107,42]; -_NTIPAliasStat["skilltelekinesis"]=[107,43]; -_NTIPAliasStat["skillfrostnova"]=[107,44]; -_NTIPAliasStat["skilliceblast"]=[107,45]; -_NTIPAliasStat["skillblaze"]=[107,46]; -_NTIPAliasStat["skillfireball"]=[107,47]; -_NTIPAliasStat["skillnova"]=[107,48]; -_NTIPAliasStat["skilllightning"]=[107,49]; -_NTIPAliasStat["skillshiverarmor"]=[107,50]; -_NTIPAliasStat["skillfirewall"]=[107,51]; -_NTIPAliasStat["skillenchant"]=[107,52]; -_NTIPAliasStat["skillchainlightning"]=[107,53]; -_NTIPAliasStat["skillteleport"]=[107,54]; -_NTIPAliasStat["skillglacialspike"]=[107,55]; -_NTIPAliasStat["skillmeteor"]=[107,56]; -_NTIPAliasStat["skillthunderstorm"]=[107,57]; -_NTIPAliasStat["skillenergyshield"]=[107,58]; -_NTIPAliasStat["skillblizzard"]=[107,59]; -_NTIPAliasStat["skillchillingarmor"]=[107,60]; -_NTIPAliasStat["skillfiremastery"]=[107,61]; -_NTIPAliasStat["skillhydra"]=[107,62]; -_NTIPAliasStat["skilllightningmastery"]=[107,63]; -_NTIPAliasStat["skillfrozenorb"]=[107,64]; -_NTIPAliasStat["skillcoldmastery"]=[107,65]; +NTIPAliasStat["skillfirebolt"] = [107,36]; +NTIPAliasStat["skillwarmth"] = [107,37]; +NTIPAliasStat["skillchargedbolt"] = [107,38]; +NTIPAliasStat["skillicebolt"] = [107,39]; +NTIPAliasStat["skillfrozenarmor"] = [107,40]; +NTIPAliasStat["skillinferno"] = [107,41]; +NTIPAliasStat["skillstaticfield"] = [107,42]; +NTIPAliasStat["skilltelekinesis"] = [107,43]; +NTIPAliasStat["skillfrostnova"] = [107,44]; +NTIPAliasStat["skilliceblast"] = [107,45]; +NTIPAliasStat["skillblaze"] = [107,46]; +NTIPAliasStat["skillfireball"] = [107,47]; +NTIPAliasStat["skillnova"] = [107,48]; +NTIPAliasStat["skilllightning"] = [107,49]; +NTIPAliasStat["skillshiverarmor"] = [107,50]; +NTIPAliasStat["skillfirewall"] = [107,51]; +NTIPAliasStat["skillenchant"] = [107,52]; +NTIPAliasStat["skillchainlightning"] = [107,53]; +NTIPAliasStat["skillteleport"] = [107,54]; +NTIPAliasStat["skillglacialspike"] = [107,55]; +NTIPAliasStat["skillmeteor"] = [107,56]; +NTIPAliasStat["skillthunderstorm"] = [107,57]; +NTIPAliasStat["skillenergyshield"] = [107,58]; +NTIPAliasStat["skillblizzard"] = [107,59]; +NTIPAliasStat["skillchillingarmor"] = [107,60]; +NTIPAliasStat["skillfiremastery"] = [107,61]; +NTIPAliasStat["skillhydra"] = [107,62]; +NTIPAliasStat["skilllightningmastery"] = [107,63]; +NTIPAliasStat["skillfrozenorb"] = [107,64]; +NTIPAliasStat["skillcoldmastery"] = [107,65]; // Necromancer skills -_NTIPAliasStat["skillamplifydamage"]=[107,66]; -_NTIPAliasStat["skillteeth"]=[107,67]; -_NTIPAliasStat["skillbonearmor"]=[107,68]; -_NTIPAliasStat["skillskeletonmastery"]=[107,69]; -_NTIPAliasStat["skillraiseskeleton"]=[107,70]; -_NTIPAliasStat["skilldimvision"]=[107,71]; -_NTIPAliasStat["skillweaken"]=[107,72]; -_NTIPAliasStat["skillpoisondagger"]=[107,73]; -_NTIPAliasStat["skillcorpseexplosion"]=[107,74]; -_NTIPAliasStat["skillclaygolem"]=[107,75]; -_NTIPAliasStat["skillironmaiden"]=[107,76]; -_NTIPAliasStat["skillterror"]=[107,77]; -_NTIPAliasStat["skillbonewall"]=[107,78]; -_NTIPAliasStat["skillgolemmastery"]=[107,79]; -_NTIPAliasStat["skillskeletalmage"]=[107,80]; -_NTIPAliasStat["skillconfuse"]=[107,81]; -_NTIPAliasStat["skilllifetap"]=[107,82]; -_NTIPAliasStat["skillpoisonexplosion"]=[107,83]; -_NTIPAliasStat["skillbonespear"]=[107,84]; -_NTIPAliasStat["skillbloodgolem"]=[107,85]; -_NTIPAliasStat["skillattract"]=[107,86]; -_NTIPAliasStat["skilldecrepify"]=[107,87]; -_NTIPAliasStat["skillboneprison"]=[107,88]; -_NTIPAliasStat["skillsummonresist"]=[107,89]; -_NTIPAliasStat["skillirongolem"]=[107,90]; -_NTIPAliasStat["skilllowerresist"]=[107,91]; -_NTIPAliasStat["skillpoisonnova"]=[107,92]; -_NTIPAliasStat["skillbonespirit"]=[107,93]; -_NTIPAliasStat["skillfiregolem"]=[107,94]; -_NTIPAliasStat["skillrevive"]=[107,95]; +NTIPAliasStat["skillamplifydamage"] = [107,66]; +NTIPAliasStat["skillteeth"] = [107,67]; +NTIPAliasStat["skillbonearmor"] = [107,68]; +NTIPAliasStat["skillskeletonmastery"] = [107,69]; +NTIPAliasStat["skillraiseskeleton"] = [107,70]; +NTIPAliasStat["skilldimvision"] = [107,71]; +NTIPAliasStat["skillweaken"] = [107,72]; +NTIPAliasStat["skillpoisondagger"] = [107,73]; +NTIPAliasStat["skillcorpseexplosion"] = [107,74]; +NTIPAliasStat["skillclaygolem"] = [107,75]; +NTIPAliasStat["skillironmaiden"] = [107,76]; +NTIPAliasStat["skillterror"] = [107,77]; +NTIPAliasStat["skillbonewall"] = [107,78]; +NTIPAliasStat["skillgolemmastery"] = [107,79]; +NTIPAliasStat["skillskeletalmage"] = [107,80]; +NTIPAliasStat["skillconfuse"] = [107,81]; +NTIPAliasStat["skilllifetap"] = [107,82]; +NTIPAliasStat["skillpoisonexplosion"] = [107,83]; +NTIPAliasStat["skillbonespear"] = [107,84]; +NTIPAliasStat["skillbloodgolem"] = [107,85]; +NTIPAliasStat["skillattract"] = [107,86]; +NTIPAliasStat["skilldecrepify"] = [107,87]; +NTIPAliasStat["skillboneprison"] = [107,88]; +NTIPAliasStat["skillsummonresist"] = [107,89]; +NTIPAliasStat["skillirongolem"] = [107,90]; +NTIPAliasStat["skilllowerresist"] = [107,91]; +NTIPAliasStat["skillpoisonnova"] = [107,92]; +NTIPAliasStat["skillbonespirit"] = [107,93]; +NTIPAliasStat["skillfiregolem"] = [107,94]; +NTIPAliasStat["skillrevive"] = [107,95]; // Paladin skills -_NTIPAliasStat["skillsacrifice"]=[107,96]; -_NTIPAliasStat["skillsmite"]=[107,97]; -_NTIPAliasStat["skillmight"]=[107,98]; -_NTIPAliasStat["skillprayer"]=[107,99]; -_NTIPAliasStat["skillresistfire"]=[107,100]; -_NTIPAliasStat["skillholybolt"]=[107,101]; -_NTIPAliasStat["skillholyfire"]=[107,102]; -_NTIPAliasStat["skillthorns"]=[107,103]; -_NTIPAliasStat["skilldefiance"]=[107,104]; -_NTIPAliasStat["skillresistcold"]=[107,105]; -_NTIPAliasStat["skillzeal"]=[107,106]; -_NTIPAliasStat["skillcharge"]=[107,107]; -_NTIPAliasStat["skillblessedaim"]=[107,108]; -_NTIPAliasStat["skillcleansing"]=[107,109]; -_NTIPAliasStat["skillresistlightning"]=[107,110]; -_NTIPAliasStat["skillvengeance"]=[107,111]; -_NTIPAliasStat["skillblessedhammer"]=[107,112]; -_NTIPAliasStat["skillconcentration"]=[107,113]; -_NTIPAliasStat["skillholyfreeze"]=[107,114]; -_NTIPAliasStat["skillvigor"]=[107,115]; -_NTIPAliasStat["skillconversion"]=[107,116]; -_NTIPAliasStat["skillholyshield"]=[107,117]; -_NTIPAliasStat["skillholyshock"]=[107,118]; -_NTIPAliasStat["skillsanctuary"]=[107,119]; -_NTIPAliasStat["skillmeditation"]=[107,120]; -_NTIPAliasStat["skillfistoftheheavens"]=[107,121]; -_NTIPAliasStat["skillfanaticism"]=[107,122]; -_NTIPAliasStat["skillconviction"]=[107,123]; -_NTIPAliasStat["skillredemption"]=[107,124]; -_NTIPAliasStat["skillsalvation"]=[107,125]; +NTIPAliasStat["skillsacrifice"] = [107,96]; +NTIPAliasStat["skillsmite"] = [107,97]; +NTIPAliasStat["skillmight"] = [107,98]; +NTIPAliasStat["skillprayer"] = [107,99]; +NTIPAliasStat["skillresistfire"] = [107,100]; +NTIPAliasStat["skillholybolt"] = [107,101]; +NTIPAliasStat["skillholyfire"] = [107,102]; +NTIPAliasStat["skillthorns"] = [107,103]; +NTIPAliasStat["skilldefiance"] = [107,104]; +NTIPAliasStat["skillresistcold"] = [107,105]; +NTIPAliasStat["skillzeal"] = [107,106]; +NTIPAliasStat["skillcharge"] = [107,107]; +NTIPAliasStat["skillblessedaim"] = [107,108]; +NTIPAliasStat["skillcleansing"] = [107,109]; +NTIPAliasStat["skillresistlightning"] = [107,110]; +NTIPAliasStat["skillvengeance"] = [107,111]; +NTIPAliasStat["skillblessedhammer"] = [107,112]; +NTIPAliasStat["skillconcentration"] = [107,113]; +NTIPAliasStat["skillholyfreeze"] = [107,114]; +NTIPAliasStat["skillvigor"] = [107,115]; +NTIPAliasStat["skillconversion"] = [107,116]; +NTIPAliasStat["skillholyshield"] = [107,117]; +NTIPAliasStat["skillholyshock"] = [107,118]; +NTIPAliasStat["skillsanctuary"] = [107,119]; +NTIPAliasStat["skillmeditation"] = [107,120]; +NTIPAliasStat["skillfistoftheheavens"] = [107,121]; +NTIPAliasStat["skillfanaticism"] = [107,122]; +NTIPAliasStat["skillconviction"] = [107,123]; +NTIPAliasStat["skillredemption"] = [107,124]; +NTIPAliasStat["skillsalvation"] = [107,125]; // Barbarian skills -_NTIPAliasStat["skillbash"]=[107,126]; -_NTIPAliasStat["skillswordmastery"]=[107,127]; -_NTIPAliasStat["skillaxemastery"]=[107,128]; -_NTIPAliasStat["skillmacemastery"]=[107,129]; -_NTIPAliasStat["skillhowl"]=[107,130]; -_NTIPAliasStat["skillfindpotion"]=[107,131]; -_NTIPAliasStat["skillleap"]=[107,132]; -_NTIPAliasStat["skilldoubleswing"]=[107,133]; -_NTIPAliasStat["skillpolearmmastery"]=[107,134]; -_NTIPAliasStat["skillthrowingmastery"]=[107,135]; -_NTIPAliasStat["skillspearmastery"]=[107,136]; -_NTIPAliasStat["skilltaunt"]=[107,137]; -_NTIPAliasStat["skillshout"]=[107,138]; -_NTIPAliasStat["skillstun"]=[107,139]; -_NTIPAliasStat["skilldoublethrow"]=[107,140]; -_NTIPAliasStat["skillincreasedstamina"]=[107,141]; -_NTIPAliasStat["skillfinditem"]=[107,142]; -_NTIPAliasStat["skillleapattack"]=[107,143]; -_NTIPAliasStat["skillconcentrate"]=[107,144]; -_NTIPAliasStat["skillironskin"]=[107,145]; -_NTIPAliasStat["skillbattlecry"]=[107,146]; -_NTIPAliasStat["skillfrenzy"]=[107,147]; -_NTIPAliasStat["skillincreasedspeed"]=[107,148]; -_NTIPAliasStat["skillbattleorders"]=[107,149]; -_NTIPAliasStat["skillgrimward"]=[107,150]; -_NTIPAliasStat["skillwhirlwind"]=[107,151]; -_NTIPAliasStat["skillberserk"]=[107,152]; -_NTIPAliasStat["skillnaturalresistance"]=[107,153]; -_NTIPAliasStat["skillwarcry"]=[107,154]; -_NTIPAliasStat["skillbattlecommand"]=[107,155]; +NTIPAliasStat["skillbash"] = [107,126]; +NTIPAliasStat["skillswordmastery"] = [107,127]; +NTIPAliasStat["skillaxemastery"] = [107,128]; +NTIPAliasStat["skillmacemastery"] = [107,129]; +NTIPAliasStat["skillhowl"] = [107,130]; +NTIPAliasStat["skillfindpotion"] = [107,131]; +NTIPAliasStat["skillleap"] = [107,132]; +NTIPAliasStat["skilldoubleswing"] = [107,133]; +NTIPAliasStat["skillpolearmmastery"] = [107,134]; +NTIPAliasStat["skillthrowingmastery"] = [107,135]; +NTIPAliasStat["skillspearmastery"] = [107,136]; +NTIPAliasStat["skilltaunt"] = [107,137]; +NTIPAliasStat["skillshout"] = [107,138]; +NTIPAliasStat["skillstun"] = [107,139]; +NTIPAliasStat["skilldoublethrow"] = [107,140]; +NTIPAliasStat["skillincreasedstamina"] = [107,141]; +NTIPAliasStat["skillfinditem"] = [107,142]; +NTIPAliasStat["skillleapattack"] = [107,143]; +NTIPAliasStat["skillconcentrate"] = [107,144]; +NTIPAliasStat["skillironskin"] = [107,145]; +NTIPAliasStat["skillbattlecry"] = [107,146]; +NTIPAliasStat["skillfrenzy"] = [107,147]; +NTIPAliasStat["skillincreasedspeed"] = [107,148]; +NTIPAliasStat["skillbattleorders"] = [107,149]; +NTIPAliasStat["skillgrimward"] = [107,150]; +NTIPAliasStat["skillwhirlwind"] = [107,151]; +NTIPAliasStat["skillberserk"] = [107,152]; +NTIPAliasStat["skillnaturalresistance"] = [107,153]; +NTIPAliasStat["skillwarcry"] = [107,154]; +NTIPAliasStat["skillbattlecommand"] = [107,155]; // Druid skills -_NTIPAliasStat["skillraven"]=[107,221]; -_NTIPAliasStat["skillpoisoncreeper"]=[107,222]; -_NTIPAliasStat["skillwerewolf"]=[107,223]; -_NTIPAliasStat["skilllycanthropy"]=[107,224]; -_NTIPAliasStat["skillfirestorm"]=[107,225]; -_NTIPAliasStat["skilloaksage"]=[107,226]; -_NTIPAliasStat["skillsummonspiritwolf"]=[107,227]; -_NTIPAliasStat["skillwerebear"]=[107,228]; -_NTIPAliasStat["skillmoltenboulder"]=[107,229]; -_NTIPAliasStat["skillarcticblast"]=[107,230]; -_NTIPAliasStat["skillfissure"]=[107,231]; -_NTIPAliasStat["skillferalrage"]=[107,232]; -_NTIPAliasStat["skillmaul"]=[107,233]; -_NTIPAliasStat["skillcarrionvine"]=[107,234]; -_NTIPAliasStat["skillcyclonearmor"]=[107,235]; -_NTIPAliasStat["skillheartofwolverine"]=[107,236]; -_NTIPAliasStat["skillsummondirewolf"]=[107,237]; -_NTIPAliasStat["skillrabies"]=[107,238]; -_NTIPAliasStat["skillfireclaws"]=[107,239]; -_NTIPAliasStat["skilltwister"]=[107,240]; -_NTIPAliasStat["skillsolarcreeper"]=[107,241]; -_NTIPAliasStat["skillhunger"]=[107,242]; -_NTIPAliasStat["skillshockwave"]=[107,243]; -_NTIPAliasStat["skillvolcano"]=[107,244]; -_NTIPAliasStat["skilltornado"]=[107,245]; -_NTIPAliasStat["skillspiritofbarbs"]=[107,246]; -_NTIPAliasStat["skillsummongrizzly"]=[107,247]; -_NTIPAliasStat["skillfury"]=[107,248]; -_NTIPAliasStat["skillarmageddon"]=[107,249]; -_NTIPAliasStat["skillhurricane"]=[107,250]; +NTIPAliasStat["skillraven"] = [107,221]; +NTIPAliasStat["skillpoisoncreeper"] = [107,222]; +NTIPAliasStat["skillwerewolf"] = [107,223]; +NTIPAliasStat["skilllycanthropy"] = [107,224]; +NTIPAliasStat["skillfirestorm"] = [107,225]; +NTIPAliasStat["skilloaksage"] = [107,226]; +NTIPAliasStat["skillsummonspiritwolf"] = [107,227]; +NTIPAliasStat["skillwerebear"] = [107,228]; +NTIPAliasStat["skillmoltenboulder"] = [107,229]; +NTIPAliasStat["skillarcticblast"] = [107,230]; +NTIPAliasStat["skillfissure"] = [107,231]; +NTIPAliasStat["skillferalrage"] = [107,232]; +NTIPAliasStat["skillmaul"] = [107,233]; +NTIPAliasStat["skillcarrionvine"] = [107,234]; +NTIPAliasStat["skillcyclonearmor"] = [107,235]; +NTIPAliasStat["skillheartofwolverine"] = [107,236]; +NTIPAliasStat["skillsummondirewolf"] = [107,237]; +NTIPAliasStat["skillrabies"] = [107,238]; +NTIPAliasStat["skillfireclaws"] = [107,239]; +NTIPAliasStat["skilltwister"] = [107,240]; +NTIPAliasStat["skillsolarcreeper"] = [107,241]; +NTIPAliasStat["skillhunger"] = [107,242]; +NTIPAliasStat["skillshockwave"] = [107,243]; +NTIPAliasStat["skillvolcano"] = [107,244]; +NTIPAliasStat["skilltornado"] = [107,245]; +NTIPAliasStat["skillspiritofbarbs"] = [107,246]; +NTIPAliasStat["skillsummongrizzly"] = [107,247]; +NTIPAliasStat["skillfury"] = [107,248]; +NTIPAliasStat["skillarmageddon"] = [107,249]; +NTIPAliasStat["skillhurricane"] = [107,250]; // Assassin skills -_NTIPAliasStat["skillfireblast"]=[107,251]; -_NTIPAliasStat["skillclawmastery"]=[107,252]; -_NTIPAliasStat["skillpsychichammer"]=[107,253]; -_NTIPAliasStat["skilltigerstrike"]=[107,254]; -_NTIPAliasStat["skilldragontalon"]=[107,255]; -_NTIPAliasStat["skillshockweb"]=[107,256]; -_NTIPAliasStat["skillbladesentinel"]=[107,257]; -_NTIPAliasStat["skillburstofspeed"]=[107,258]; -_NTIPAliasStat["skillfistsoffire"]=[107,259]; -_NTIPAliasStat["skilldragonclaw"]=[107,260]; -_NTIPAliasStat["skillchargedboltsentry"]=[107,261]; -_NTIPAliasStat["skillwakeoffire"]=[107,262]; -_NTIPAliasStat["skillweaponblock"]=[107,263]; -_NTIPAliasStat["skillcloakofshadows"]=[107,264]; -_NTIPAliasStat["skillcobrastrike"]=[107,265]; -_NTIPAliasStat["skillbladefury"]=[107,266]; -_NTIPAliasStat["skillfade"]=[107,267]; -_NTIPAliasStat["skillshadowwarrior"]=[107,268]; -_NTIPAliasStat["skillclawsofthunder"]=[107,269]; -_NTIPAliasStat["skilldragontail"]=[107,270]; -_NTIPAliasStat["skilllightningsentry"]=[107,271]; -_NTIPAliasStat["skillwakeofinferno"]=[107,272]; -_NTIPAliasStat["skillmindblast"]=[107,273]; -_NTIPAliasStat["skillbladesofice"]=[107,274]; -_NTIPAliasStat["skilldragonflight"]=[107,275]; -_NTIPAliasStat["skilldeathsentry"]=[107,276]; -_NTIPAliasStat["skillbladeshield"]=[107,277]; -_NTIPAliasStat["skillvenom"]=[107,278]; -_NTIPAliasStat["skillshadowmaster"]=[107,279]; -_NTIPAliasStat["skillphoenixstrike"]=[107,280]; +NTIPAliasStat["skillfireblast"] = [107,251]; +NTIPAliasStat["skillclawmastery"] = [107,252]; +NTIPAliasStat["skillpsychichammer"] = [107,253]; +NTIPAliasStat["skilltigerstrike"] = [107,254]; +NTIPAliasStat["skilldragontalon"] = [107,255]; +NTIPAliasStat["skillshockweb"] = [107,256]; +NTIPAliasStat["skillbladesentinel"] = [107,257]; +NTIPAliasStat["skillburstofspeed"] = [107,258]; +NTIPAliasStat["skillfistsoffire"] = [107,259]; +NTIPAliasStat["skilldragonclaw"] = [107,260]; +NTIPAliasStat["skillchargedboltsentry"] = [107,261]; +NTIPAliasStat["skillwakeoffire"] = [107,262]; +NTIPAliasStat["skillweaponblock"] = [107,263]; +NTIPAliasStat["skillcloakofshadows"] = [107,264]; +NTIPAliasStat["skillcobrastrike"] = [107,265]; +NTIPAliasStat["skillbladefury"] = [107,266]; +NTIPAliasStat["skillfade"] = [107,267]; +NTIPAliasStat["skillshadowwarrior"] = [107,268]; +NTIPAliasStat["skillclawsofthunder"] = [107,269]; +NTIPAliasStat["skilldragontail"] = [107,270]; +NTIPAliasStat["skilllightningsentry"] = [107,271]; +NTIPAliasStat["skillwakeofinferno"] = [107,272]; +NTIPAliasStat["skillmindblast"] = [107,273]; +NTIPAliasStat["skillbladesofice"] = [107,274]; +NTIPAliasStat["skilldragonflight"] = [107,275]; +NTIPAliasStat["skilldeathsentry"] = [107,276]; +NTIPAliasStat["skillbladeshield"] = [107,277]; +NTIPAliasStat["skillvenom"] = [107,278]; +NTIPAliasStat["skillshadowmaster"] = [107,279]; +NTIPAliasStat["skillphoenixstrike"] = [107,280]; -_NTIPAliasStat["itemrestinpeace"]=108; -_NTIPAliasStat["curseresistance"]=109; -_NTIPAliasStat["itempoisonlengthresist"]=110; -_NTIPAliasStat["itemnormaldamage"]=111; -_NTIPAliasStat["itemhowl"]=112; -_NTIPAliasStat["itemstupidity"]=113; -_NTIPAliasStat["itemdamagetomana"]=114; -_NTIPAliasStat["itemignoretargetac"]=115; -_NTIPAliasStat["itemfractionaltargetac"]=116; -_NTIPAliasStat["itempreventheal"]=117; -_NTIPAliasStat["itemhalffreezeduration"]=118; -_NTIPAliasStat["itemtohitpercent"]=119; -_NTIPAliasStat["itemdamagetargetac"]=120; -_NTIPAliasStat["itemdemondamagepercent"]=121; -_NTIPAliasStat["itemundeaddamagepercent"]=122; -_NTIPAliasStat["itemdemontohit"]=123; -_NTIPAliasStat["itemundeadtohit"]=124; -_NTIPAliasStat["itemthrowable"]=125; -_NTIPAliasStat["itemelemskill"]=126; -_NTIPAliasStat["itemallskills"]=127; -_NTIPAliasStat["itemattackertakeslightdamage"]=128; -_NTIPAliasStat["ironmaidenlevel"]=129; -_NTIPAliasStat["lifetaplevel"]=130; -_NTIPAliasStat["thornspercent"]=131; -_NTIPAliasStat["bonearmor"]=132; -_NTIPAliasStat["bonearmormax"]=133; -_NTIPAliasStat["itemfreeze"]=134; -_NTIPAliasStat["itemopenwounds"]=135; -_NTIPAliasStat["itemcrushingblow"]=136; -_NTIPAliasStat["itemkickdamage"]=137; -_NTIPAliasStat["itemmanaafterkill"]=138; -_NTIPAliasStat["itemhealafterdemonkill"]=139; -_NTIPAliasStat["itemextrablood"]=140; -_NTIPAliasStat["itemdeadlystrike"]=141; -_NTIPAliasStat["itemabsorbfirepercent"]=142; -_NTIPAliasStat["itemabsorbfire"]=143; -_NTIPAliasStat["itemabsorblightpercent"]=144; -_NTIPAliasStat["itemabsorblight"]=145; -_NTIPAliasStat["itemabsorbmagicpercent"]=146; -_NTIPAliasStat["itemabsorbmagic"]=147; -_NTIPAliasStat["itemabsorbcoldpercent"]=148; -_NTIPAliasStat["itemabsorbcold"]=149; -_NTIPAliasStat["itemslow"]=150; +NTIPAliasStat["itemrestinpeace"] = 108; +NTIPAliasStat["curseresistance"] = 109; +NTIPAliasStat["itempoisonlengthresist"] = 110; +NTIPAliasStat["itemnormaldamage"] = 111; +NTIPAliasStat["itemhowl"] = 112; +NTIPAliasStat["itemstupidity"] = 113; +NTIPAliasStat["itemdamagetomana"] = 114; +NTIPAliasStat["itemignoretargetac"] = 115; +NTIPAliasStat["itemfractionaltargetac"] = 116; +NTIPAliasStat["itempreventheal"] = 117; +NTIPAliasStat["itemhalffreezeduration"] = 118; +NTIPAliasStat["itemtohitpercent"] = 119; +NTIPAliasStat["itemdamagetargetac"] = 120; +NTIPAliasStat["itemdemondamagepercent"] = 121; +NTIPAliasStat["itemundeaddamagepercent"] = 122; +NTIPAliasStat["itemdemontohit"] = 123; +NTIPAliasStat["itemundeadtohit"] = 124; +NTIPAliasStat["itemthrowable"] = 125; +NTIPAliasStat["itemelemskill"] = 126; +NTIPAliasStat["itemallskills"] = 127; +NTIPAliasStat["itemattackertakeslightdamage"] = 128; +NTIPAliasStat["ironmaidenlevel"] = 129; +NTIPAliasStat["lifetaplevel"] = 130; +NTIPAliasStat["thornspercent"] = 131; +NTIPAliasStat["bonearmor"] = 132; +NTIPAliasStat["bonearmormax"] = 133; +NTIPAliasStat["itemfreeze"] = 134; +NTIPAliasStat["itemopenwounds"] = 135; +NTIPAliasStat["itemcrushingblow"] = 136; +NTIPAliasStat["itemkickdamage"] = 137; +NTIPAliasStat["itemmanaafterkill"] = 138; +NTIPAliasStat["itemhealafterdemonkill"] = 139; +NTIPAliasStat["itemextrablood"] = 140; +NTIPAliasStat["itemdeadlystrike"] = 141; +NTIPAliasStat["itemabsorbfirepercent"] = 142; +NTIPAliasStat["itemabsorbfire"] = 143; +NTIPAliasStat["itemabsorblightpercent"] = 144; +NTIPAliasStat["itemabsorblight"] = 145; +NTIPAliasStat["itemabsorbmagicpercent"] = 146; +NTIPAliasStat["itemabsorbmagic"] = 147; +NTIPAliasStat["itemabsorbcoldpercent"] = 148; +NTIPAliasStat["itemabsorbcold"] = 149; +NTIPAliasStat["itemslow"] = 150; -_NTIPAliasStat["itemaura"]=151; -_NTIPAliasStat["mightaura"]=[151,98]; -_NTIPAliasStat["holyfireaura"]=[151,102]; -_NTIPAliasStat["thornsaura"]=[151,103]; -_NTIPAliasStat["defianceaura"]=[151,104]; -_NTIPAliasStat["concentrationaura"]=[151,113]; -_NTIPAliasStat["holyfreezeaura"]=[151,114]; -_NTIPAliasStat["vigoraura"]=[151,115]; -_NTIPAliasStat["holyshockaura"]=[151,118]; -_NTIPAliasStat["sanctuaryaura"]=[151,119]; -_NTIPAliasStat["meditationaura"]=[151,120]; -_NTIPAliasStat["fanaticismaura"]=[151,122]; -_NTIPAliasStat["convictionaura"]=[151,123]; -_NTIPAliasStat["redemptionaura"]=[151,124]; +NTIPAliasStat["itemaura"] = 151; +NTIPAliasStat["mightaura"] = [151,98]; +NTIPAliasStat["holyfireaura"] = [151,102]; +NTIPAliasStat["thornsaura"] = [151,103]; +NTIPAliasStat["defianceaura"] = [151,104]; +NTIPAliasStat["concentrationaura"] = [151,113]; +NTIPAliasStat["holyfreezeaura"] = [151,114]; +NTIPAliasStat["vigoraura"] = [151,115]; +NTIPAliasStat["holyshockaura"] = [151,118]; +NTIPAliasStat["sanctuaryaura"] = [151,119]; +NTIPAliasStat["meditationaura"] = [151,120]; +NTIPAliasStat["fanaticismaura"] = [151,122]; +NTIPAliasStat["convictionaura"] = [151,123]; +NTIPAliasStat["redemptionaura"] = [151,124]; -_NTIPAliasStat["itemindestructible"]=152; -_NTIPAliasStat["itemcannotbefrozen"]=153; -_NTIPAliasStat["itemstaminadrainpct"]=154; -_NTIPAliasStat["itemreanimate"]=155; -_NTIPAliasStat["itempierce"]=156; -_NTIPAliasStat["itemmagicarrow"]=157; -_NTIPAliasStat["itemexplosivearrow"]=158; -_NTIPAliasStat["itemthrowmindamage"]=159; -_NTIPAliasStat["itemthrowmaxdamage"]=160; -_NTIPAliasStat["itemskillhandofathena"]=161; -_NTIPAliasStat["itemskillstaminapercent"]=162; -_NTIPAliasStat["itemskillpassivestaminapercent"]=163; -_NTIPAliasStat["itemskillconcentration"]=164; -_NTIPAliasStat["itemskillenchant"]=165; -_NTIPAliasStat["itemskillpierce"]=166; -_NTIPAliasStat["itemskillconviction"]=167; -_NTIPAliasStat["itemskillchillingarmor"]=168; -_NTIPAliasStat["itemskillfrenzy"]=169; -_NTIPAliasStat["itemskilldecrepify"]=170; -_NTIPAliasStat["itemskillarmorpercent"]=171; -_NTIPAliasStat["alignment"]=172; -_NTIPAliasStat["target0"]=173; -_NTIPAliasStat["target1"]=174; -_NTIPAliasStat["goldlost"]=175; -_NTIPAliasStat["conversionlevel"]=176; -_NTIPAliasStat["conversionmaxhp"]=177; -_NTIPAliasStat["unitdooverlay"]=178; -_NTIPAliasStat["attackvsmontype"]=179; -_NTIPAliasStat["damagevsmontype"]=180; -_NTIPAliasStat["fade"]=181; -_NTIPAliasStat["armoroverridepercent"]=182; -_NTIPAliasStat["unused183"]=183; -_NTIPAliasStat["unused184"]=184; -_NTIPAliasStat["unused185"]=185; -_NTIPAliasStat["unused186"]=186; -_NTIPAliasStat["unused187"]=187; +NTIPAliasStat["itemindestructible"] = 152; +NTIPAliasStat["itemcannotbefrozen"] = 153; +NTIPAliasStat["itemstaminadrainpct"] = 154; +NTIPAliasStat["itemreanimate"] = 155; +NTIPAliasStat["itempierce"] = 156; +NTIPAliasStat["itemmagicarrow"] = 157; +NTIPAliasStat["itemexplosivearrow"] = 158; +NTIPAliasStat["itemthrowmindamage"] = 159; +NTIPAliasStat["itemthrowmaxdamage"] = 160; +NTIPAliasStat["itemskillhandofathena"] = 161; +NTIPAliasStat["itemskillstaminapercent"] = 162; +NTIPAliasStat["itemskillpassivestaminapercent"] = 163; +NTIPAliasStat["itemskillconcentration"] = 164; +NTIPAliasStat["itemskillenchant"] = 165; +NTIPAliasStat["itemskillpierce"] = 166; +NTIPAliasStat["itemskillconviction"] = 167; +NTIPAliasStat["itemskillchillingarmor"] = 168; +NTIPAliasStat["itemskillfrenzy"] = 169; +NTIPAliasStat["itemskilldecrepify"] = 170; +NTIPAliasStat["itemskillarmorpercent"] = 171; +NTIPAliasStat["alignment"] = 172; +NTIPAliasStat["target0"] = 173; +NTIPAliasStat["target1"] = 174; +NTIPAliasStat["goldlost"] = 175; +NTIPAliasStat["conversionlevel"] = 176; +NTIPAliasStat["conversionmaxhp"] = 177; +NTIPAliasStat["unitdooverlay"] = 178; +NTIPAliasStat["attackvsmontype"] = 179; +NTIPAliasStat["damagevsmontype"] = 180; +NTIPAliasStat["fade"] = 181; +NTIPAliasStat["armoroverridepercent"] = 182; +NTIPAliasStat["unused183"] = 183; +NTIPAliasStat["unused184"] = 184; +NTIPAliasStat["unused185"] = 185; +NTIPAliasStat["unused186"] = 186; +NTIPAliasStat["unused187"] = 187; -_NTIPAliasStat["itemaddskilltab"]=188; -_NTIPAliasStat["itemaddbowandcrossbowskilltab"]=[188,0]; _NTIPAliasStat["bowandcrossbowskilltab"]=[188,0]; -_NTIPAliasStat["itemaddpassiveandmagicskilltab"]=[188,1]; _NTIPAliasStat["passiveandmagicskilltab"]=[188,1]; -_NTIPAliasStat["itemaddjavelinandspearskilltab"]=[188,2]; _NTIPAliasStat["javelinandspearskilltab"]=[188,2]; -_NTIPAliasStat["itemaddfireskilltab"]=[188,8]; _NTIPAliasStat["fireskilltab"]=[188,8]; -_NTIPAliasStat["itemaddlightningskilltab"]=[188,9]; _NTIPAliasStat["lightningskilltab"]=[188,9]; -_NTIPAliasStat["itemaddcoldskilltab"]=[188,10]; _NTIPAliasStat["coldskilltab"]=[188,10]; -_NTIPAliasStat["itemaddcursesskilltab"]=[188,16]; _NTIPAliasStat["cursesskilltab"]=[188,16]; -_NTIPAliasStat["itemaddpoisonandboneskilltab"]=[188,17]; _NTIPAliasStat["poisonandboneskilltab"]=[188,17]; -_NTIPAliasStat["itemaddnecromancersummoningskilltab"]=[188,18]; _NTIPAliasStat["necromancersummoningskilltab"]=[188,18]; -_NTIPAliasStat["itemaddpalicombatskilltab"]=[188,24]; _NTIPAliasStat["palicombatskilltab"]=[188,24]; -_NTIPAliasStat["itemaddoffensiveaurasskilltab"]=[188,25]; _NTIPAliasStat["offensiveaurasskilltab"]=[188,25]; -_NTIPAliasStat["itemadddefensiveaurasskilltab"]=[188,26]; _NTIPAliasStat["defensiveaurasskilltab"]=[188,26]; -_NTIPAliasStat["itemaddbarbcombatskilltab"]=[188,32]; _NTIPAliasStat["barbcombatskilltab"]=[188,32]; -_NTIPAliasStat["itemaddmasteriesskilltab"]=[188,33]; _NTIPAliasStat["masteriesskilltab"]=[188,33]; -_NTIPAliasStat["itemaddwarcriesskilltab"]=[188,34]; _NTIPAliasStat["warcriesskilltab"]=[188,34]; -_NTIPAliasStat["itemadddruidsummoningskilltab"]=[188,40]; _NTIPAliasStat["druidsummoningskilltab"]=[188,40]; -_NTIPAliasStat["itemaddshapeshiftingskilltab"]=[188,41]; _NTIPAliasStat["shapeshiftingskilltab"]=[188,41]; -_NTIPAliasStat["itemaddelementalskilltab"]=[188,42]; _NTIPAliasStat["elementalskilltab"]=[188,42]; -_NTIPAliasStat["itemaddtrapsskilltab"]=[188,48]; _NTIPAliasStat["trapsskilltab"]=[188,48]; -_NTIPAliasStat["itemaddshadowdisciplinesskilltab"]=[188,49]; _NTIPAliasStat["shadowdisciplinesskilltab"]=[188,49]; -_NTIPAliasStat["itemaddmartialartsskilltab"]=[188,50]; _NTIPAliasStat["martialartsskilltab"]=[188,50]; +NTIPAliasStat["itemaddskilltab"] = 188; +NTIPAliasStat["itemaddbowandcrossbowskilltab"] = [188,0]; NTIPAliasStat["bowandcrossbowskilltab"] = [188,0]; +NTIPAliasStat["itemaddpassiveandmagicskilltab"] = [188,1]; NTIPAliasStat["passiveandmagicskilltab"] = [188,1]; +NTIPAliasStat["itemaddjavelinandspearskilltab"] = [188,2]; NTIPAliasStat["javelinandspearskilltab"] = [188,2]; +NTIPAliasStat["itemaddfireskilltab"] = [188,8]; NTIPAliasStat["fireskilltab"] = [188,8]; +NTIPAliasStat["itemaddlightningskilltab"] = [188,9]; NTIPAliasStat["lightningskilltab"] = [188,9]; +NTIPAliasStat["itemaddcoldskilltab"] = [188,10]; NTIPAliasStat["coldskilltab"] = [188,10]; +NTIPAliasStat["itemaddcursesskilltab"] = [188,16]; NTIPAliasStat["cursesskilltab"] = [188,16]; +NTIPAliasStat["itemaddpoisonandboneskilltab"] = [188,17]; NTIPAliasStat["poisonandboneskilltab"] = [188,17]; +NTIPAliasStat["itemaddnecromancersummoningskilltab"] = [188,18]; NTIPAliasStat["necromancersummoningskilltab"] = [188,18]; +NTIPAliasStat["itemaddpalicombatskilltab"] = [188,24]; NTIPAliasStat["palicombatskilltab"] = [188,24]; +NTIPAliasStat["itemaddoffensiveaurasskilltab"] = [188,25]; NTIPAliasStat["offensiveaurasskilltab"] = [188,25]; +NTIPAliasStat["itemadddefensiveaurasskilltab"] = [188,26]; NTIPAliasStat["defensiveaurasskilltab"] = [188,26]; +NTIPAliasStat["itemaddbarbcombatskilltab"] = [188,32]; NTIPAliasStat["barbcombatskilltab"] = [188,32]; +NTIPAliasStat["itemaddmasteriesskilltab"] = [188,33]; NTIPAliasStat["masteriesskilltab"] = [188,33]; +NTIPAliasStat["itemaddwarcriesskilltab"] = [188,34]; NTIPAliasStat["warcriesskilltab"] = [188,34]; +NTIPAliasStat["itemadddruidsummoningskilltab"] = [188,40]; NTIPAliasStat["druidsummoningskilltab"] = [188,40]; +NTIPAliasStat["itemaddshapeshiftingskilltab"] = [188,41]; NTIPAliasStat["shapeshiftingskilltab"] = [188,41]; +NTIPAliasStat["itemaddelementalskilltab"] = [188,42]; NTIPAliasStat["elementalskilltab"] = [188,42]; +NTIPAliasStat["itemaddtrapsskilltab"] = [188,48]; NTIPAliasStat["trapsskilltab"] = [188,48]; +NTIPAliasStat["itemaddshadowdisciplinesskilltab"] = [188,49]; NTIPAliasStat["shadowdisciplinesskilltab"] = [188,49]; +NTIPAliasStat["itemaddmartialartsskilltab"] = [188,50]; NTIPAliasStat["martialartsskilltab"] = [188,50]; -_NTIPAliasStat["unused189"]=189; -_NTIPAliasStat["unused190"]=190; -_NTIPAliasStat["unused191"]=191; -_NTIPAliasStat["unused192"]=192; -_NTIPAliasStat["unused193"]=193; -_NTIPAliasStat["itemnumsockets"]=194; _NTIPAliasStat["sockets"]=194; -_NTIPAliasStat["itemskillonattack"]=195; -_NTIPAliasStat["itemskillonkill"]=196; -_NTIPAliasStat["itemskillondeath"]=197; +NTIPAliasStat["unused189"] = 189; +NTIPAliasStat["unused190"] = 190; +NTIPAliasStat["unused191"] = 191; +NTIPAliasStat["unused192"] = 192; +NTIPAliasStat["unused193"] = 193; +NTIPAliasStat["itemnumsockets"] = 194; NTIPAliasStat["sockets"] = 194; +NTIPAliasStat["itemskillonattack"] = 195; +NTIPAliasStat["itemskillonkill"] = 196; +NTIPAliasStat["itemskillondeath"] = 197; -_NTIPAliasStat["itemskillonhit"]=198; -_NTIPAliasStat["amplifydamageonhit"]=[198,4225]; +NTIPAliasStat["itemskillonhit"] = 198; +NTIPAliasStat["amplifydamageonhit"] = [198,4225]; -_NTIPAliasStat["itemskillonlevelup"]=199; -_NTIPAliasStat["unused200"]=200; -_NTIPAliasStat["itemskillongethit"]=201; -_NTIPAliasStat["unused202"]=202; -_NTIPAliasStat["unused203"]=203; -_NTIPAliasStat["itemchargedskill"]=204; +NTIPAliasStat["itemskillonlevelup"] = 199; +NTIPAliasStat["unused200"] = 200; +NTIPAliasStat["itemskillongethit"] = 201; +NTIPAliasStat["unused202"] = 202; +NTIPAliasStat["unused203"] = 203; -_NTIPAliasStat["teleportcharges"]=[204,3461]; +NTIPAliasStat["itemchargedskill"] = 204; +NTIPAliasStat["teleportcharges"] = [204,3461]; -_NTIPAliasStat["unused204"]=205; -_NTIPAliasStat["unused205"]=206; -_NTIPAliasStat["unused206"]=207; -_NTIPAliasStat["unused207"]=208; -_NTIPAliasStat["unused208"]=209; -_NTIPAliasStat["unused209"]=210; -_NTIPAliasStat["unused210"]=211; -_NTIPAliasStat["unused211"]=212; -_NTIPAliasStat["unused212"]=213; -_NTIPAliasStat["itemarmorperlevel"]=214; -_NTIPAliasStat["itemarmorpercentperlevel"]=215; -_NTIPAliasStat["itemhpperlevel"]=216; -_NTIPAliasStat["itemmanaperlevel"]=217; -_NTIPAliasStat["itemmaxdamageperlevel"]=218; -_NTIPAliasStat["itemmaxdamagepercentperlevel"]=219; -_NTIPAliasStat["itemstrengthperlevel"]=220; -_NTIPAliasStat["itemdexterityperlevel"]=221; -_NTIPAliasStat["itemenergyperlevel"]=222; -_NTIPAliasStat["itemvitalityperlevel"]=223; -_NTIPAliasStat["itemtohitperlevel"]=224; -_NTIPAliasStat["itemtohitpercentperlevel"]=225; -_NTIPAliasStat["itemcolddamagemaxperlevel"]=226; -_NTIPAliasStat["itemfiredamagemaxperlevel"]=227; -_NTIPAliasStat["itemltngdamagemaxperlevel"]=228; -_NTIPAliasStat["itempoisdamagemaxperlevel"]=229; -_NTIPAliasStat["itemresistcoldperlevel"]=230; -_NTIPAliasStat["itemresistfireperlevel"]=231; -_NTIPAliasStat["itemresistltngperlevel"]=232; -_NTIPAliasStat["itemresistpoisperlevel"]=233; -_NTIPAliasStat["itemabsorbcoldperlevel"]=234; -_NTIPAliasStat["itemabsorbfireperlevel"]=235; -_NTIPAliasStat["itemabsorbltngperlevel"]=236; -_NTIPAliasStat["itemabsorbpoisperlevel"]=237; -_NTIPAliasStat["itemthornsperlevel"]=238; -_NTIPAliasStat["itemfindgoldperlevel"]=239; -_NTIPAliasStat["itemfindmagicperlevel"]=240; -_NTIPAliasStat["itemregenstaminaperlevel"]=241; -_NTIPAliasStat["itemstaminaperlevel"]=242; -_NTIPAliasStat["itemdamagedemonperlevel"]=243; -_NTIPAliasStat["itemdamageundeadperlevel"]=244; -_NTIPAliasStat["itemtohitdemonperlevel"]=245; -_NTIPAliasStat["itemtohitundeadperlevel"]=246; -_NTIPAliasStat["itemcrushingblowperlevel"]=247; -_NTIPAliasStat["itemopenwoundsperlevel"]=248; -_NTIPAliasStat["itemkickdamageperlevel"]=249; -_NTIPAliasStat["itemdeadlystrikeperlevel"]=250; -_NTIPAliasStat["itemfindgemsperlevel"]=251; -_NTIPAliasStat["itemreplenishdurability"]=252; -_NTIPAliasStat["itemreplenishquantity"]=253; -_NTIPAliasStat["itemextrastack"]=254; -_NTIPAliasStat["itemfinditem"]=255; -_NTIPAliasStat["itemslashdamage"]=256; -_NTIPAliasStat["itemslashdamagepercent"]=257; -_NTIPAliasStat["itemcrushdamage"]=258; -_NTIPAliasStat["itemcrushdamagepercent"]=259; -_NTIPAliasStat["itemthrustdamage"]=260; -_NTIPAliasStat["itemthrustdamagepercent"]=261; -_NTIPAliasStat["itemabsorbslash"]=262; -_NTIPAliasStat["itemabsorbcrush"]=263; -_NTIPAliasStat["itemabsorbthrust"]=264; -_NTIPAliasStat["itemabsorbslashpercent"]=265; -_NTIPAliasStat["itemabsorbcrushpercent"]=266; -_NTIPAliasStat["itemabsorbthrustpercent"]=267; -_NTIPAliasStat["itemarmorbytime"]=268; -_NTIPAliasStat["itemarmorpercentbytime"]=269; -_NTIPAliasStat["itemhpbytime"]=270; -_NTIPAliasStat["itemmanabytime"]=271; -_NTIPAliasStat["itemmaxdamagebytime"]=272; -_NTIPAliasStat["itemmaxdamagepercentbytime"]=273; -_NTIPAliasStat["itemstrengthbytime"]=274; -_NTIPAliasStat["itemdexteritybytime"]=275; -_NTIPAliasStat["itemenergybytime"]=276; -_NTIPAliasStat["itemvitalitybytime"]=277; -_NTIPAliasStat["itemtohitbytime"]=278; -_NTIPAliasStat["itemtohitpercentbytime"]=279; -_NTIPAliasStat["itemcolddamagemaxbytime"]=280; -_NTIPAliasStat["itemfiredamagemaxbytime"]=281; -_NTIPAliasStat["itemltngdamagemaxbytime"]=282; -_NTIPAliasStat["itempoisdamagemaxbytime"]=283; -_NTIPAliasStat["itemresistcoldbytime"]=284; -_NTIPAliasStat["itemresistfirebytime"]=285; -_NTIPAliasStat["itemresistltngbytime"]=286; -_NTIPAliasStat["itemresistpoisbytime"]=287; -_NTIPAliasStat["itemabsorbcoldbytime"]=288; -_NTIPAliasStat["itemabsorbfirebytime"]=289; -_NTIPAliasStat["itemabsorbltngbytime"]=290; -_NTIPAliasStat["itemabsorbpoisbytime"]=291; -_NTIPAliasStat["itemfindgoldbytime"]=292; -_NTIPAliasStat["itemfindmagicbytime"]=293; -_NTIPAliasStat["itemregenstaminabytime"]=294; -_NTIPAliasStat["itemstaminabytime"]=295; -_NTIPAliasStat["itemdamagedemonbytime"]=296; -_NTIPAliasStat["itemdamageundeadbytime"]=297; -_NTIPAliasStat["itemtohitdemonbytime"]=298; -_NTIPAliasStat["itemtohitundeadbytime"]=299; -_NTIPAliasStat["itemcrushingblowbytime"]=300; -_NTIPAliasStat["itemopenwoundsbytime"]=301; -_NTIPAliasStat["itemkickdamagebytime"]=302; -_NTIPAliasStat["itemdeadlystrikebytime"]=303; -_NTIPAliasStat["itemfindgemsbytime"]=304; -_NTIPAliasStat["itempiercecold"]=305; -_NTIPAliasStat["itempiercefire"]=306; -_NTIPAliasStat["itempierceltng"]=307; -_NTIPAliasStat["itempiercepois"]=308; -_NTIPAliasStat["itemdamagevsmonster"]=309; -_NTIPAliasStat["itemdamagepercentvsmonster"]=310; -_NTIPAliasStat["itemtohitvsmonster"]=311; -_NTIPAliasStat["itemtohitpercentvsmonster"]=312; -_NTIPAliasStat["itemacvsmonster"]=313; -_NTIPAliasStat["itemacpercentvsmonster"]=314; -_NTIPAliasStat["firelength"]=315; -_NTIPAliasStat["burningmin"]=316; -_NTIPAliasStat["burningmax"]=317; -_NTIPAliasStat["progressivedamage"]=318; -_NTIPAliasStat["progressivesteal"]=319; -_NTIPAliasStat["progressiveother"]=320; -_NTIPAliasStat["progressivefire"]=321; -_NTIPAliasStat["progressivecold"]=322; -_NTIPAliasStat["progressivelightning"]=323; -_NTIPAliasStat["itemextracharges"]=324; -_NTIPAliasStat["progressivetohit"]=325; -_NTIPAliasStat["poisoncount"]=326; -_NTIPAliasStat["damageframerate"]=327; -_NTIPAliasStat["pierceidx"]=328; -_NTIPAliasStat["passivefiremastery"]=329; -_NTIPAliasStat["passiveltngmastery"]=330; -_NTIPAliasStat["passivecoldmastery"]=331; -_NTIPAliasStat["passivepoismastery"]=332; -_NTIPAliasStat["passivefirepierce"]=333; -_NTIPAliasStat["passiveltngpierce"]=334; -_NTIPAliasStat["passivecoldpierce"]=335; -_NTIPAliasStat["passivepoispierce"]=336; -_NTIPAliasStat["passivecriticalstrike"]=337; -_NTIPAliasStat["passivedodge"]=338; -_NTIPAliasStat["passiveavoid"]=339; -_NTIPAliasStat["passiveevade"]=340; -_NTIPAliasStat["passivewarmth"]=341; -_NTIPAliasStat["passivemasterymeleeth"]=342; -_NTIPAliasStat["passivemasterymeleedmg"]=343; -_NTIPAliasStat["passivemasterymeleecrit"]=344; -_NTIPAliasStat["passivemasterythrowth"]=345; -_NTIPAliasStat["passivemasterythrowdmg"]=346; -_NTIPAliasStat["passivemasterythrowcrit"]=347; -_NTIPAliasStat["passiveweaponblock"]=348; -_NTIPAliasStat["passivesummonresist"]=349; -_NTIPAliasStat["modifierlistskill"]=350; -_NTIPAliasStat["modifierlistlevel"]=351; -_NTIPAliasStat["lastsenthppct"]=352; -_NTIPAliasStat["sourceunittype"]=353; -_NTIPAliasStat["sourceunitid"]=354; -_NTIPAliasStat["shortparam1"]=355; -_NTIPAliasStat["questitemdifficulty"]=356; -_NTIPAliasStat["passivemagmastery"]=357; -_NTIPAliasStat["passivemagpierce"]=358; +NTIPAliasStat["unused204"] = 205; +NTIPAliasStat["unused205"] = 206; +NTIPAliasStat["unused206"] = 207; +NTIPAliasStat["unused207"] = 208; +NTIPAliasStat["unused208"] = 209; +NTIPAliasStat["unused209"] = 210; +NTIPAliasStat["unused210"] = 211; +NTIPAliasStat["unused211"] = 212; +NTIPAliasStat["unused212"] = 213; +NTIPAliasStat["itemarmorperlevel"] = 214; +NTIPAliasStat["itemarmorpercentperlevel"] = 215; +NTIPAliasStat["itemhpperlevel"] = 216; +NTIPAliasStat["itemmanaperlevel"] = 217; +NTIPAliasStat["itemmaxdamageperlevel"] = 218; +NTIPAliasStat["itemmaxdamagepercentperlevel"] = 219; +NTIPAliasStat["itemstrengthperlevel"] = 220; +NTIPAliasStat["itemdexterityperlevel"] = 221; +NTIPAliasStat["itemenergyperlevel"] = 222; +NTIPAliasStat["itemvitalityperlevel"] = 223; +NTIPAliasStat["itemtohitperlevel"] = 224; +NTIPAliasStat["itemtohitpercentperlevel"] = 225; +NTIPAliasStat["itemcolddamagemaxperlevel"] = 226; +NTIPAliasStat["itemfiredamagemaxperlevel"] = 227; +NTIPAliasStat["itemltngdamagemaxperlevel"] = 228; +NTIPAliasStat["itempoisdamagemaxperlevel"] = 229; +NTIPAliasStat["itemresistcoldperlevel"] = 230; +NTIPAliasStat["itemresistfireperlevel"] = 231; +NTIPAliasStat["itemresistltngperlevel"] = 232; +NTIPAliasStat["itemresistpoisperlevel"] = 233; +NTIPAliasStat["itemabsorbcoldperlevel"] = 234; +NTIPAliasStat["itemabsorbfireperlevel"] = 235; +NTIPAliasStat["itemabsorbltngperlevel"] = 236; +NTIPAliasStat["itemabsorbpoisperlevel"] = 237; +NTIPAliasStat["itemthornsperlevel"] = 238; +NTIPAliasStat["itemfindgoldperlevel"] = 239; +NTIPAliasStat["itemfindmagicperlevel"] = 240; +NTIPAliasStat["itemregenstaminaperlevel"] = 241; +NTIPAliasStat["itemstaminaperlevel"] = 242; +NTIPAliasStat["itemdamagedemonperlevel"] = 243; +NTIPAliasStat["itemdamageundeadperlevel"] = 244; +NTIPAliasStat["itemtohitdemonperlevel"] = 245; +NTIPAliasStat["itemtohitundeadperlevel"] = 246; +NTIPAliasStat["itemcrushingblowperlevel"] = 247; +NTIPAliasStat["itemopenwoundsperlevel"] = 248; +NTIPAliasStat["itemkickdamageperlevel"] = 249; +NTIPAliasStat["itemdeadlystrikeperlevel"] = 250; +NTIPAliasStat["itemfindgemsperlevel"] = 251; +NTIPAliasStat["itemreplenishdurability"] = 252; +NTIPAliasStat["itemreplenishquantity"] = 253; +NTIPAliasStat["itemextrastack"] = 254; +NTIPAliasStat["itemfinditem"] = 255; +NTIPAliasStat["itemslashdamage"] = 256; +NTIPAliasStat["itemslashdamagepercent"] = 257; +NTIPAliasStat["itemcrushdamage"] = 258; +NTIPAliasStat["itemcrushdamagepercent"] = 259; +NTIPAliasStat["itemthrustdamage"] = 260; +NTIPAliasStat["itemthrustdamagepercent"] = 261; +NTIPAliasStat["itemabsorbslash"] = 262; +NTIPAliasStat["itemabsorbcrush"] = 263; +NTIPAliasStat["itemabsorbthrust"] = 264; +NTIPAliasStat["itemabsorbslashpercent"] = 265; +NTIPAliasStat["itemabsorbcrushpercent"] = 266; +NTIPAliasStat["itemabsorbthrustpercent"] = 267; +NTIPAliasStat["itemarmorbytime"] = 268; +NTIPAliasStat["itemarmorpercentbytime"] = 269; +NTIPAliasStat["itemhpbytime"] = 270; +NTIPAliasStat["itemmanabytime"] = 271; +NTIPAliasStat["itemmaxdamagebytime"] = 272; +NTIPAliasStat["itemmaxdamagepercentbytime"] = 273; +NTIPAliasStat["itemstrengthbytime"] = 274; +NTIPAliasStat["itemdexteritybytime"] = 275; +NTIPAliasStat["itemenergybytime"] = 276; +NTIPAliasStat["itemvitalitybytime"] = 277; +NTIPAliasStat["itemtohitbytime"] = 278; +NTIPAliasStat["itemtohitpercentbytime"] = 279; +NTIPAliasStat["itemcolddamagemaxbytime"] = 280; +NTIPAliasStat["itemfiredamagemaxbytime"] = 281; +NTIPAliasStat["itemltngdamagemaxbytime"] = 282; +NTIPAliasStat["itempoisdamagemaxbytime"] = 283; +NTIPAliasStat["itemresistcoldbytime"] = 284; +NTIPAliasStat["itemresistfirebytime"] = 285; +NTIPAliasStat["itemresistltngbytime"] = 286; +NTIPAliasStat["itemresistpoisbytime"] = 287; +NTIPAliasStat["itemabsorbcoldbytime"] = 288; +NTIPAliasStat["itemabsorbfirebytime"] = 289; +NTIPAliasStat["itemabsorbltngbytime"] = 290; +NTIPAliasStat["itemabsorbpoisbytime"] = 291; +NTIPAliasStat["itemfindgoldbytime"] = 292; +NTIPAliasStat["itemfindmagicbytime"] = 293; +NTIPAliasStat["itemregenstaminabytime"] = 294; +NTIPAliasStat["itemstaminabytime"] = 295; +NTIPAliasStat["itemdamagedemonbytime"] = 296; +NTIPAliasStat["itemdamageundeadbytime"] = 297; +NTIPAliasStat["itemtohitdemonbytime"] = 298; +NTIPAliasStat["itemtohitundeadbytime"] = 299; +NTIPAliasStat["itemcrushingblowbytime"] = 300; +NTIPAliasStat["itemopenwoundsbytime"] = 301; +NTIPAliasStat["itemkickdamagebytime"] = 302; +NTIPAliasStat["itemdeadlystrikebytime"] = 303; +NTIPAliasStat["itemfindgemsbytime"] = 304; +NTIPAliasStat["itempiercecold"] = 305; +NTIPAliasStat["itempiercefire"] = 306; +NTIPAliasStat["itempierceltng"] = 307; +NTIPAliasStat["itempiercepois"] = 308; +NTIPAliasStat["itemdamagevsmonster"] = 309; +NTIPAliasStat["itemdamagepercentvsmonster"] = 310; +NTIPAliasStat["itemtohitvsmonster"] = 311; +NTIPAliasStat["itemtohitpercentvsmonster"] = 312; +NTIPAliasStat["itemacvsmonster"] = 313; +NTIPAliasStat["itemacpercentvsmonster"] = 314; +NTIPAliasStat["firelength"] = 315; +NTIPAliasStat["burningmin"] = 316; +NTIPAliasStat["burningmax"] = 317; +NTIPAliasStat["progressivedamage"] = 318; +NTIPAliasStat["progressivesteal"] = 319; +NTIPAliasStat["progressiveother"] = 320; +NTIPAliasStat["progressivefire"] = 321; +NTIPAliasStat["progressivecold"] = 322; +NTIPAliasStat["progressivelightning"] = 323; +NTIPAliasStat["itemextracharges"] = 324; +NTIPAliasStat["progressivetohit"] = 325; +NTIPAliasStat["poisoncount"] = 326; +NTIPAliasStat["damageframerate"] = 327; +NTIPAliasStat["pierceidx"] = 328; +NTIPAliasStat["passivefiremastery"] = 329; +NTIPAliasStat["passiveltngmastery"] = 330; +NTIPAliasStat["passivecoldmastery"] = 331; +NTIPAliasStat["passivepoismastery"] = 332; +NTIPAliasStat["passivefirepierce"] = 333; +NTIPAliasStat["passiveltngpierce"] = 334; +NTIPAliasStat["passivecoldpierce"] = 335; +NTIPAliasStat["passivepoispierce"] = 336; +NTIPAliasStat["passivecriticalstrike"] = 337; +NTIPAliasStat["passivedodge"] = 338; +NTIPAliasStat["passiveavoid"] = 339; +NTIPAliasStat["passiveevade"] = 340; +NTIPAliasStat["passivewarmth"] = 341; +NTIPAliasStat["passivemasterymeleeth"] = 342; +NTIPAliasStat["passivemasterymeleedmg"] = 343; +NTIPAliasStat["passivemasterymeleecrit"] = 344; +NTIPAliasStat["passivemasterythrowth"] = 345; +NTIPAliasStat["passivemasterythrowdmg"] = 346; +NTIPAliasStat["passivemasterythrowcrit"] = 347; +NTIPAliasStat["passiveweaponblock"] = 348; +NTIPAliasStat["passivesummonresist"] = 349; +NTIPAliasStat["modifierlistskill"] = 350; +NTIPAliasStat["modifierlistlevel"] = 351; +NTIPAliasStat["lastsenthppct"] = 352; +NTIPAliasStat["sourceunittype"] = 353; +NTIPAliasStat["sourceunitid"] = 354; +NTIPAliasStat["shortparam1"] = 355; +NTIPAliasStat["questitemdifficulty"] = 356; +NTIPAliasStat["passivemagmastery"] = 357; +NTIPAliasStat["passivemagpierce"] = 358; diff --git a/d2bs/kolbot/libs/NTItemParser.dbl b/d2bs/kolbot/libs/NTItemParser.dbl index 14abff02f..fffaaf9de 100644 --- a/d2bs/kolbot/libs/NTItemParser.dbl +++ b/d2bs/kolbot/libs/NTItemParser.dbl @@ -1,427 +1,586 @@ -/* +/* -[Item-parser Syntax Information] +[Item-parser Syntax Information] -1. [Keyword] separates into two groups - - [Property Keywords] : [Type], [Name], [Class], [Quality], [Flag], [Level], [Prefix], [Suffix] - - [Stat Keywords] : [Number or Alias] +1. [Keyword] separates into two groups + - [Property Keywords] : [Type], [Name], [Class], [Quality], [Flag], [Level], [Prefix], [Suffix] + - [Stat Keywords] : [Number or Alias] -2. [Keyword] must be surrounded by '[' and ']' +2. [Keyword] must be surrounded by '[' and ']' -3. [Property Keywords] must be placed first +3. [Property Keywords] must be placed first -4. Insert '#' symbol between [Property Keywords] and [Stat Keywords] +4. Insert '#' symbol between [Property Keywords] and [Stat Keywords] -5. Use '+', '-', '*', '/', '(', ')', '&&', '||', '>', '>=', '<', '<=', '==', '!=' symbols for comparison +5. Use '+', '-', '*', '/', '(', ')', '&&', '||', '>', '>=', '<', '<=', '==', '!=' symbols for comparison -6. Use '//' symbol for comment +6. Use '//' symbol for comment */ -include("NTItemAlias.dbl"); +include("NTItemAlias.dbl"); -var _NTIP_CheckList = new Array(); -var stringArray = []; +var NTIP = {}, + NTIP_CheckList = [], + stringArray = []; -function NTIPOpenFile(filepath) -{ - var _nipfile; - var _line; - var string; - var count = 0; +NTIP.OpenFile = function (filepath, notify) { + if (!FileTools.exists(filepath)) { + if (notify) { + Misc.errorReport("ÿc1NIP file doesn't exist: ÿc0" + filepath); + } + + return false; + } + + var i, nipfile, line, lines, info, item, + tick = getTickCount(), + filename = filepath.substring(filepath.lastIndexOf("/") + 1, filepath.length), + entries = 0; + + try { + nipfile = File.open(filepath, 0); + } catch (fileError) { + if (notify) { + Misc.errorReport("ÿc1Failed to load NIP: ÿc0" + filename); + } + } + + if (!nipfile) { + return false; + } + + lines = nipfile.readAllLines(); + + nipfile.close(); - _nipfile = File.open(filepath, 0); + for (i = 0; i < lines.length; i += 1) { + info = { + line: i + 1, + file: filename, + string: lines[i] + }; - if(!_nipfile) - return false; + line = NTIP.ParseLineInt(lines[i], info); - while(!_nipfile.eof) - { - string = _nipfile.readLine(); - _line = NTIPParseLineInt(string); - count += 1; + if (line) { + entries += 1; - if (_line) { - _NTIP_CheckList.push(_line); - stringArray.push({string: string, count: count, file: filepath}); + NTIP_CheckList.push(line); + stringArray.push(info); } } - _nipfile.close(); + if (notify) { + print("ÿc4Loaded NIP: ÿc2" + filename + "ÿc4. Lines: ÿc2" + lines.length + "ÿc4. Valid entries: ÿc2" + entries + ". ÿc4Time: ÿc2" + (getTickCount() - tick) + " ms"); + } + + return true; +}; + +/*NTIP.Minify = function (filepath) { + var i, nipfile, lines, hash, fileList, + filename = filepath.substring(filepath.lastIndexOf("/") + 1, filepath.length); - return true; -} + try { + nipfile = File.open(filepath, 0); + } catch (fileError) { -function NTIPCheckItem(item, list) -{ - if (!list) { - list = _NTIP_CheckList; } - var i; - var _identified; - var _result = 0; + if (!nipfile) { + return false; + } - _identified = item.getFlag(0x10); - - for(i = 0 ; i < list.length ; i++) - { - try { - if(list[i][0].length > 0) - { - if(eval(list[i][0])) - { - if(list[i][1].length > 0) - { - if(eval(list[i][1])) - { - if(list[i][2] && list[i][2]["MaxQuantity"] && !isNaN(list[i][2]["MaxQuantity"])) - { - if(NTIP_CheckQuantityOwned(list[i][0],list[i][1], false) < list[i][2]["MaxQuantity"]) - { - //print("I need more of these "+NTC_ItemQualityToMGRColor[item.quality] + item.itemdesc.split("\n")[0].substring(3)); - return 1; - } - else - { - //print("I already have enough of these "+NTC_ItemQualityToMGRColor[item.quality] + item.itemdesc.split("\n")[0].substring(3)+" in my stash!"); - return 0; + hash = md5_file(filepath); + lines = nipfile.readAllLines(); + + nipfile.close(); + + for (i = 0; i < lines.length; i += 1) { + lines[i] = lines[i].replace(/\s+/g, "").toLowerCase(); + } + + Misc.fileAction("pickit/minified/" + hash + "." + filename, 1, lines.join("\n")); + + fileList = dopen("pickit/minified/").getFiles(); + + for (i = 0; i < fileList.length; i += 1) { + if (fileList[i].indexOf(filename) > -1 && fileList[i].indexOf(hash) === -1) { + FileTools.remove("pickit/minified/" + fileList[i]); + } + } + + return true; +};*/ + +NTIP.CheckQuantityOwned = function (item_type, item_stats) { + var i, item, + num = 0, + items = me.getItems(); + + if (!items) { + print("I can't find my items!"); + + return 0; + } + + for (i = 0; i < items.length; i += 1) { + if (items[i].mode === 0 && items[i].location === 7) { + item = items[i]; + + 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) { + num += 1; + } + } + } else if (items[i].mode === 0 && items[i].location === 3) { // inv check + item = items[i]; + + 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 + num += 1; + //} + } + } + } + } + + //print("I have "+num+" of these."); + + return num; +}; + +NTIP.Clear = function () { + NTIP_CheckList = []; + 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 - { - //print("No maximum for this item"); - return 1; + } else { + if (NTIP_CheckList[i][2].Tier > tier) { + tier = NTIP_CheckList[i][2].Tier; } } - else if(!_identified && _result == 0) - _result = -1; } - else - { - if(list[i][2] && list[i][2]["MaxQuantity"] && !isNaN(list[i][2]["MaxQuantity"])) - { - if(NTIP_CheckQuantityOwned(list[i][0], null, false) < list[i][2]["MaxQuantity"]) - { - //print("I need more of these "+NTC_ItemQualityToMGRColor[item.quality] + item.itemdesc.split("\n")[0].substring(3)); - return 1; + } 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, + rval = {}, + result = 0; + + if (!entryList) { + list = NTIP_CheckList; + } else { + list = entryList; + } + + identified = item.getFlag(0x10); + + for (i = 0; i < list.length; i += 1) { + try { + if (list[i][0].length > 0) { + if (eval(list[i][0])) { + if (list[i][1].length > 0) { + if (eval(list[i][1])) { + if (list[i][2] && list[i][2].MaxQuantity && !isNaN(list[i][2].MaxQuantity)) { + num = NTIP.CheckQuantityOwned(list[i][0], list[i][1]); + + if (num < list[i][2].MaxQuantity) { + result = 1; + + break; + } else { + if (item.getParent() && item.getParent().name === me.name && item.mode === 0 && num === list[i][2].MaxQuantity) { // attempt at inv fix for maxquantity + result = 1; + + break; + } + } + } else { + result = 1; + + break; } - else - { - //print("I already have enough of these "+NTC_ItemQualityToMGRColor[item.quality] + item.itemdesc.split("\n")[0].substring(3)+" in my stash!"); - return 0; + } else if (!identified && result === 0) { + result = -1; + + if (verbose) { + rval.line = stringArray[i].file + " #" + stringArray[i].line; } } - else - { - //print("No maximum for this item"); - return 1; + } else { + if (list[i][2] && list[i][2].MaxQuantity && !isNaN(list[i][2].MaxQuantity)) { + num = NTIP.CheckQuantityOwned(list[i][0], null); + + if (num < list[i][2].MaxQuantity) { + result = 1; + + break; + } else { + if (item.getParent() && item.getParent().name === me.name && item.mode === 0 && num === list[i][2].MaxQuantity) { // attempt at inv fix for maxquantity + result = 1; + + break; + } + } + } else { + result = 1; + + break; } } } - } - else if(list[i][1].length > 0) - { - if(eval(list[i][1])) - { - if(list[i][2] && list[i][2]["MaxQuantity"] && !isNaN(list[i][2]["MaxQuantity"])) - { - if(NTIP_CheckQuantityOwned(null, list[i][1], false) < list[i][2]["MaxQuantity"]) - { - //print("I need more of these "+NTC_ItemQualityToMGRColor[item.quality] + item.itemdesc.split("\n")[0].substring(3)); - return 1; - } - else - { - //print("I already have enough of these "+NTC_ItemQualityToMGRColor[item.quality] + item.itemdesc.split("\n")[0].substring(3)+" in my stash!"); - return 0; + } else if (list[i][1].length > 0) { + if (eval(list[i][1])) { + if (list[i][2] && list[i][2].MaxQuantity && !isNaN(list[i][2].MaxQuantity)) { + num = NTIP.CheckQuantityOwned(null, list[i][1]); + + if (num < list[i][2].MaxQuantity) { + result = 1; + + break; + } else { + if (item.getParent() && item.getParent().name === me.name && item.mode === 0 && num === list[i][2].MaxQuantity) { // attempt at inv fix for maxquantity + result = 1; + + break; + } } + } else { + result = 1; + + break; } - else - { - return 1; + } else if (!identified && result === 0) { + result = -1; + + if (verbose) { + rval.line = stringArray[i].file + " #" + stringArray[i].line; } } - else if(!_identified && _result == 0) - _result = -1; } } catch (pickError) { showConsole(); - if (arguments.length === 1) { - print("ÿc1Pickit error! Line # ÿc2" + stringArray[i].count + " ÿc1Entry: ÿc0" + stringArray[i].string + " (" + stringArray[i].file + ")"); + if (!entryList) { + 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 + NTIP_CheckList[i] = ["", "", ""]; // make the bad entry blank } else { - print("ÿc1Pickit error in runeword config!"); + Misc.errorReport("ÿc1Pickit error in runeword config!"); } + + result = 0; } } - return _result; -} - -// Internal function -function NTIP_CheckQuantityOwned(item_type, item_stats, check_inventory_too) -{ - var _nb = 0; - var _items = me.getItems(); - if (!_items) - { - print("I can't find my items!"); - return 0; - } - for(var i = 0 ; i < _items.length ; i++) - { - if(_items[i].mode == 0 && _items[i].location == 7) - { - var item = _items[i]; - 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) - _nb++; - } - else if(check_inventory_too && _items[i].mode == 0 && _items[i].location == 3) - { - var item = _items[i]; - 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 - _nb++; + if (verbose) { + switch (result) { + case -1: + break; + case 1: + rval.line = stringArray[i].file + " #" + stringArray[i].line; + + break; + default: + rval.line = null; + + break; } + + rval.result = result; + + return rval; + } + + return result; +}; + +NTIP.IsSyntaxInt = function (ch) { + return (ch === '!' || ch === '%' || ch === '&' || (ch >= '(' && ch <= '+') || ch === '-' || ch === '/' || (ch >= ':' && ch <= '?') || ch === '|'); +}; + +NTIP.ParseLineInt = function (input, info) { + var i, property, p_start, p_end, p_section, p_keyword, p_result, value; + + p_end = input.indexOf("//"); + + if (p_end !== -1) { + input = input.substring(0, p_end); + } + + input = input.replace(/\s+/g, "").toLowerCase(); + + if (input.length < 5) { + return null; } - //print("I have "+_nb+" of these."); - return _nb; -} - -function NTIPParseLineInt(input) -{ - var i; - var _start, _end; - var _section, _keyword; - var _result; - - _end = input.indexOf("//"); - if(_end != -1) - input = input.substring(0, _end); - - input = input.replace(/ |;|\t/g, "").toLowerCase(); - - if(input.length < 5) - return null; - - _result = input.split("#"); - - if(_result[0] && _result[0].length > 4) - { - _section = _result[0].split("["); - - _result[0] = _section[0]; - - for(i = 1 ; i < _section.length ; i++) - { - _end = _section[i].indexOf("]") + 1; - - switch(_section[i][0]) - { - case 't': - _result[0] += "item.itemType"; - break; - case 'n': - _result[0] += "item.classid"; - break; - case 'c': - _result[0] += "item.itemclass"; - break; - case 'q': - _result[0] += "item.quality"; - break; - case 'f': - if(_section[i][_end] == '!') - _result[0] += "!item.getFlag("; - else - _result[0] += "item.getFlag("; - - _end += 2; + + p_result = input.split("#"); + + if (p_result[0] && p_result[0].length > 4) { + p_section = p_result[0].split("["); + + p_result[0] = p_section[0]; + + for (i = 1; i < p_section.length; i += 1) { + p_end = p_section[i].indexOf("]") + 1; + property = p_section[i].substring(0, p_end - 1); + + switch (property) { + case 'color': + p_result[0] += "item.getColor()"; + + break; + case 'type': + p_result[0] += "item.itemType"; + + break; + case 'name': + p_result[0] += "item.classid"; + + break; + case 'class': + p_result[0] += "item.itemclass"; + + break; + case 'quality': + p_result[0] += "item.quality"; + + break; + case 'flag': + if (p_section[i][p_end] === '!') { + p_result[0] += "!item.getFlag("; + } else { + p_result[0] += "item.getFlag("; + } + + p_end += 2; break; - case 'l': - _result[0] += "item.ilvl"; - break; - case 'p': - //_result[0] += "item.prefixnum"; - if(_section[i][_end] == '!') - _result[0] += "!item.getPrefix("; - else - _result[0] += "item.getPrefix("; - - _end += 2; + case 'level': + p_result[0] += "item.ilvl"; break; - case 's': - //_result[0] += "item.suffixnum"; - if(_section[i][_end] == '!') - _result[0] += "!item.getSuffix("; - else - _result[0] += "item.getSuffix("; + case 'prefix': + if (p_section[i][p_end] === '!') { + p_result[0] += "!item.getPrefix("; + } else { + p_result[0] += "item.getPrefix("; + } - _end += 2; + p_end += 2; break; - default: - print("Unknown Keyword : " + input); - break; + case 'suffix': + if (p_section[i][p_end] === '!') { + p_result[0] += "!item.getSuffix("; + } else { + p_result[0] += "item.getSuffix("; + } + + p_end += 2; + + break; + default: + Misc.errorReport("Unknown property: " + property + " File: " + info.file + " Line: " + info.line); + + return false; } - for(_start = _end ; _end < _section[i].length ; _end++) - { - if(!NTIPIsSyntaxInt(_section[i][_end])) - break; + for (p_start = p_end; p_end < p_section[i].length; p_end += 1) { + if (!NTIP.IsSyntaxInt(p_section[i][p_end])) { + break; + } } - _result[0] += _section[i].substring(_start, _end); + 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); - for(_start = _end ; _end < _section[i].length ; _end++) - { - if(NTIPIsSyntaxInt(_section[i][_end])) - break; + return false; } - _keyword = _section[i].substring(_start, _end); + for (p_start = p_end; p_end < p_section[i].length; p_end += 1) { + if (NTIP.IsSyntaxInt(p_section[i][p_end])) { + break; + } + } - if(isNaN(_keyword)) - { - switch(_section[i][0]) - { - case 't': - if (typeof _NTIPAliasType[_keyword] === "undefined") { - _result[0] += "false"; - } else { - _result[0] += _NTIPAliasType[_keyword]; + p_keyword = p_section[i].substring(p_start, p_end); + + if (isNaN(p_keyword)) { + switch (property) { + case 'color': + if (NTIPAliasColor[p_keyword] === undefined) { + Misc.errorReport("Unknown color: " + p_keyword + " File: " + info.file + " Line: " + info.line); + + return false; } - break; - case 'n': - if (typeof _NTIPAliasClassID[_keyword] === "undefined") { - _result[0] += "false"; - } else { - _result[0] += _NTIPAliasClassID[_keyword]; + p_result[0] += NTIPAliasColor[p_keyword]; + + break; + case 'type': + if (NTIPAliasType[p_keyword] === undefined) { + Misc.errorReport("Unknown type: " + p_keyword + " File: " + info.file + " Line: " + info.line); + + return false; } - - break; - case 'c': - if (typeof _NTIPAliasClass[_keyword] === "undefined") { - _result[0] += "false"; - } else { - _result[0] += _NTIPAliasClass[_keyword]; + + p_result[0] += NTIPAliasType[p_keyword]; + + break; + case 'name': + if (NTIPAliasClassID[p_keyword] === undefined) { + Misc.errorReport("Unknown name: " + p_keyword + " File: " + info.file + " Line: " + info.line); + + return false; } - - break; - case 'q': - if (typeof _NTIPAliasQuality[_keyword] === "undefined") { - _result[0] += "false"; - } else { - _result[0] += _NTIPAliasQuality[_keyword]; + + p_result[0] += NTIPAliasClassID[p_keyword]; + + break; + case 'class': + if (NTIPAliasClass[p_keyword] === undefined) { + Misc.errorReport("Unknown class: " + p_keyword + " File: " + info.file + " Line: " + info.line); + + return false; } - - break; - case 'f': - if (typeof _NTIPAliasFlag[_keyword] === "undefined") { - _result[0] += "false)"; - } else { - _result[0] += _NTIPAliasFlag[_keyword] + ")"; + + p_result[0] += NTIPAliasClass[p_keyword]; + + break; + case 'quality': + if (NTIPAliasQuality[p_keyword] === undefined) { + Misc.errorReport("Unknown quality: " + p_keyword + " File: " + info.file + " Line: " + info.line); + + return false; } - break; + p_result[0] += NTIPAliasQuality[p_keyword]; + + break; + case 'flag': + if (NTIPAliasFlag[p_keyword] === undefined) { + Misc.errorReport("Unknown flag: " + p_keyword + " File: " + info.file + " Line: " + info.line); + + return false; + } + + p_result[0] += NTIPAliasFlag[p_keyword] + ")"; + + break; + case 'prefix': + case 'suffix': + p_result[0] += "\"" + p_keyword + "\")"; + + break; + } + } else { + if (property === 'flag' || property === 'prefix' || property === 'suffix') { + p_result[0] += p_keyword + ")"; + } else { + p_result[0] += p_keyword; } - } - else - { - if(_section[i][0] == 'f' || _section[i][0] == 'p' || _section[i][0] == 's') - _result[0] += _keyword + ")"; - else - _result[0] += _keyword; } - _result[0] += _section[i].substring(_end); + p_result[0] += p_section[i].substring(p_end); } + } else { + p_result[0] = ""; } - else - _result[0] = ""; - - if(_result[1] && _result[1].length > 4) - { - _section = _result[1].split("["); - _result[1] = _section[0]; - - for(i = 1 ; i < _section.length ; i++) - { - _end = _section[i].indexOf("]"); - _keyword = _section[i].substring(0, _end); - - if (isNaN(_keyword)) { - if (typeof _NTIPAliasStat[_keyword] === "undefined") { - _result[1] += "false"; - } else { - _result[1] += "item.getStat(" + _NTIPAliasStat[_keyword] + ")"; + + if (p_result[1] && p_result[1].length > 4) { + p_section = p_result[1].split("["); + p_result[1] = p_section[0]; + + for (i = 1; i < p_section.length; i += 1) { + p_end = p_section[i].indexOf("]"); + p_keyword = p_section[i].substring(0, p_end); + + if (isNaN(p_keyword)) { + if (NTIPAliasStat[p_keyword] === undefined) { + Misc.errorReport("Unknown stat: " + p_keyword + " File: " + info.file + " Line: " + info.line); + + return false; } + + p_result[1] += "item.getStatEx(" + NTIPAliasStat[p_keyword] + ")"; } else { - _result[1] += "item.getStat(" + _keyword + ")"; + p_result[1] += "item.getStatEx(" + p_keyword + ")"; } - _result[1] += _section[i].substring(_end+1); + p_result[1] += p_section[i].substring(p_end + 1); } + } else { + p_result[1] = ""; } - else - _result[1] = ""; - - if(_result[2] && _result[2].replace(/^\s+|\s+$/, "").length > 0) - { - _section = _result[2].split("["); - _result[2] = new Array(); - - for(i = 1 ; i < _section.length ; i++) - { - _end = _section[i].indexOf("]"); - - _keyword = _section[i].substring(0, _end); - - if(_keyword.toLowerCase().replace(/^\s+|\s+$/, "") == "maxquantity") - { - _end = _section[i].split("==")[1].replace(/^\s+|\s+$/, "").indexOf("//"); - if(_end == -1) - _end = _section[i].split("==")[1].replace(/^\s+|\s+$/, "").length; - var _quantity = parseInt(_section[i].split("==")[1].replace(/^\s+|\s+$/, "").substring(0, _end)); - _result[2]["MaxQuantity"] = _quantity; - } - else - { - print("Error in your NIP file : unknown 3rd part keyword."); - } - } - } - - return _result; -} -function NTIPIsSyntaxInt(ch) -{ - return (ch == '!' || ch == '%' || ch == '&' || (ch >= '(' && ch <= '+') || ch == '-' || ch == '/' || (ch >= ':' && ch <= '?') || ch == '|'); -} + if (p_result[2] && p_result[2].length > 0) { + p_section = p_result[2].split("["); + p_result[2] = {}; -// prototypes + for (i = 1; i < p_section.length; i += 1) { + p_end = p_section[i].indexOf("]"); + p_keyword = p_section[i].substring(0, p_end); -Unit.prototype.__defineGetter__('itemclass', - function() { - if (getBaseStat(0, this.classid, 'code') === undefined) { - return 0; - } - - if (getBaseStat(0, this.classid, 'code') === getBaseStat(0, this.classid, 'ultracode')) { - return 2; - } else if (getBaseStat(0, this.classid, 'code') === getBaseStat(0, this.classid, 'ubercode')) { - return 1; - } else { - return 0; + switch (p_keyword.toLowerCase()) { + case "maxquantity": + value = Number(p_section[i].split("==")[1].match(/\d+/g)); + + if (!isNaN(value)) { + p_result[2].MaxQuantity = value; + } + + break; + case "tier": + value = Number(p_section[i].split("==")[1].match(/\d+/g)); + + if (!isNaN(value)) { + p_result[2].Tier = value; + } + + break; + default: + Misc.errorReport("Unknown 3rd part keyword: " + p_keyword.toLowerCase()); + + return false; + } } } -); \ No newline at end of file + + return p_result; +}; \ No newline at end of file diff --git a/d2bs/kolbot/libs/OOG.js b/d2bs/kolbot/libs/OOG.js index 8ce2685cf..c23e28fcb 100644 --- a/d2bs/kolbot/libs/OOG.js +++ b/d2bs/kolbot/libs/OOG.js @@ -5,51 +5,346 @@ */ var D2Bot = { - printToConsole: function (msg) { - sendCopyData(null, "D2Bot #", 0, "printToConsole;" + msg); + handle: 0, + + init: function () { + var handle = DataFile.getStats().handle; + + if (handle) { + this.handle = handle; + } + + return this.handle; + }, + + sendMessage: function (handle, mode, msg) { + sendCopyData(null, handle, mode, msg); + }, + + printToConsole: function (msg, color, tooltip, trigger) { + var printObj = { + msg: msg, + color: color || 0, + tooltip: tooltip || "", + trigger: trigger || "" + }, + + obj = { + profile: me.profile, + func: "printToConsole", + args: [JSON.stringify(printObj)] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); + }, + + printToItemLog: function (itemObj) { + var obj = { + profile: me.profile, + func: "printToItemLog", + args: [JSON.stringify(itemObj)] + }; + + 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)); }, - printToItemLog: function (msg) { - sendCopyData(null, "D2Bot #", 0, "printToItemLog;" + msg); + + 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, + func: "saveItem", + args: [JSON.stringify(itemObj)] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); }, + updateStatus: function (msg) { - sendCopyData(null, "D2Bot #", 0, "updateStatus;" + msg); + var obj = { + profile: me.profile, + func: "updateStatus", + args: [msg] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); }, + updateRuns: function () { - sendCopyData(null, "D2Bot #", 0, "updateRuns"); + var obj = { + profile: me.profile, + func: "updateRuns", + args: [] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); }, + updateChickens: function () { - sendCopyData(null, "D2Bot #", 0, "updateChickens"); + var obj = { + profile: me.profile, + func: "updateChickens", + args: [] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); + }, + + updateDeaths: function () { + var obj = { + profile: me.profile, + func: "updateDeaths", + args: [] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); }, + requestGameInfo: function () { - sendCopyData(null, "D2Bot #", 0, "requestGameInfo"); + var obj = { + profile: me.profile, + func: "requestGameInfo", + args: [] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); }, - restart: function (reset) { - if (arguments.length > 0) { - sendCopyData(null, "D2Bot #", 0, "restartProfile;" + reset.toString()); - } else { - sendCopyData(null, "D2Bot #", 0, "restartProfile"); - } + + restart: function (keySwap) { + var obj = { + profile: me.profile, + func: "restartProfile", + args: arguments.length > 0 ? [me.profile, keySwap] : [me.profile] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); }, + CDKeyInUse: function () { - sendCopyData(null, "D2Bot #", 0, "CDKeyInUse"); + var obj = { + profile: me.profile, + func: "CDKeyInUse", + args: [] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); }, + CDKeyDisabled: function () { - sendCopyData(null, "D2Bot #", 0, "CDKeyDisabled"); - }, - joinMe: function (window, gameName, gameCount, gamePass, isUp) { - sendCopyData(null, window, 1, gameName + gameCount + "/" + gamePass + "/" + isUp); + var obj = { + profile: me.profile, + func: "CDKeyDisabled", + args: [] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); }, - requestGame: function (who) { - sendCopyData(null, who, 3, me.profile); + + CDKeyRD: function () { + var obj = { + profile: me.profile, + func: "CDKeyRD", + args: [] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); }, - stop: function () { - sendCopyData(null, "D2Bot #", 0, "stop"); //this stops current window + + stop: function (profile, release) { + if (!profile) { + profile = me.profile; + } + + if (release === undefined) { + release = false; + } + + var obj = { + profile: me.profile, + func: "stop", + args: [profile, release] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); }, + start: function (profile) { - sendCopyData(null, "D2Bot #", 0, "start;" + profile); //this starts a particular profile.ini + var obj = { + profile: me.profile, + func: "start", + args: [profile] + }; + + 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, + func: "updateCount", + args: ["1"] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); + }, + + shoutGlobal: function (msg, mode) { + var obj = { + profile: me.profile, + func: "shoutGlobal", + args: [msg, mode] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); + }, + + heartBeat: function () { + var obj = { + profile: me.profile, + func: "heartBeat", + args: [] + }; + + //print("ÿc1Heart beat " + this.handle); + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); + }, + + sendWinMsg: function (wparam, lparam) { + var obj = { + profile: me.profile, + func: "winmsg", + args: [wparam, lparam] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); }, - updateCount: function () { - sendCopyData(null, "D2Bot #", 0, "updateCount"); + + ingame: function () { + this.sendWinMsg(0x0086, 0x0000); + this.sendWinMsg(0x0006, 0x0002); + this.sendWinMsg(0x001c, 0x0000); + }, + + // Profile to profile communication + joinMe: function (profile, gameName, gameCount, gamePass, isUp) { + var obj = { + gameName: gameName + gameCount, + gamePass: gamePass, + inGame: isUp === "yes" + }; + + sendCopyData(null, profile, 1, JSON.stringify(obj)); + }, + + requestGame: function (profile) { + var obj = { + profile: me.profile + }; + + sendCopyData(null, profile, 3, JSON.stringify(obj)); + }, + + // Store info in d2bot# cache + store: function (info) { + this.remove(); + + var obj = { + profile: me.profile, + func: "store", + args: [me.profile, info] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); + }, + + // Get info from d2bot# cache + retrieve: function () { + var obj = { + profile: me.profile, + func: "retrieve", + args: [me.profile] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); + }, + + // Delete info from d2bot# cache + remove: function () { + var obj = { + profile: me.profile, + func: "delete", + args: [me.profile] + }; + + sendCopyData(null, this.handle, 0, JSON.stringify(obj)); } }; @@ -63,106 +358,189 @@ var DataFile = { deaths: 0, lastArea: "", gold: 0, - level: 0 + level: 0, + name: "", + gameName: "", + ingameTick: 0, + handle: 0, + nextGame: "" }; string = JSON.stringify(obj); - FileTools.writeText("data/" + me.profile + ".json", string); + //FileTools.writeText("data/" + me.profile + ".json", string); + Misc.fileAction("data/" + me.profile + ".json", 1, string); + + return obj; }, - getStats: function () { + getObj: function () { var obj, string; if (!FileTools.exists("data/" + me.profile + ".json")) { DataFile.create(); } - string = FileTools.readText("data/" + me.profile + ".json"); - obj = JSON.parse(string); + //string = FileTools.readText("data/" + me.profile + ".json"); + string = Misc.fileAction("data/" + me.profile + ".json", 0); + + try { + obj = JSON.parse(string); + } catch (e) { + // If we failed, file might be corrupted, so create a new one + obj = this.create(); + } + + if (obj) { + return obj; + } + + print("Error reading DataFile. Using null values."); + + return {runs: 0, experience: 0, lastArea: "", gold: 0, level: 0, name: "", gameName: "", ingameTick: 0, handle: 0, nextGame: ""}; + }, + + getStats: function () { + var obj = this.getObj(); - return {runs: obj.runs, experience: obj.experience, lastArea: obj.lastArea, gold: obj.gold, level: obj.level}; + return Misc.clone(obj); }, updateStats: function (arg, value) { - var obj, string; + while (me.ingame && !me.gameReady) { + delay(100); + } - string = FileTools.readText("data/" + me.profile + ".json"); - obj = JSON.parse(string); + var i, obj, string, + statArr = []; - switch (arg) { - case "runs": - obj.runs = value; + if (typeof arg === "object") { + statArr = arg.slice(); + } - break; - case "experience": - obj.experience = me.getStat(13); - obj.level = me.getStat(12); + if (typeof arg === "string") { + statArr.push(arg); + } - break; - case "lastArea": - if (obj.lastArea === getArea().name) { - return; - } + obj = this.getObj(); - obj.lastArea = getArea().name; + for (i = 0; i < statArr.length; i += 1) { + switch (statArr[i]) { + case "experience": + obj.experience = me.getStat(Stats.experience); + obj.level = me.getStat(Stats.level); - break; - case "gold": - obj.gold = me.getStat(14) + me.getStat(15); + break; + case "lastArea": + if (obj.lastArea === Pather.getAreaName(me.area)) { + return; + } - break; - } + obj.lastArea = Pather.getAreaName(me.area); - string = JSON.stringify(obj); + break; + case "gold": + if (!me.gameReady) { + break; + } - FileTools.writeText("data/" + me.profile + ".json", string); - }, + obj.gold = me.getStat(Stats.gold) + me.getStat(Stats.goldbank); - updateDeaths: function () { - var obj, string; + break; + case "name": + obj.name = me.name; + + break; + case "ingameTick": + obj.ingameTick = getTickCount(); + + break; + case "deaths": + obj.deaths = (obj.deaths || 0) + 1; + + break; + default: + obj[statArr[i]] = value; + + break; + } + } - string = FileTools.readText("data/" + me.profile + ".json"); - obj = JSON.parse(string); - obj.deaths = obj.deaths + 1; string = JSON.stringify(obj); - FileTools.writeText("data/" + me.profile + ".json", string); + //FileTools.writeText("data/" + me.profile + ".json", string); + Misc.fileAction("data/" + me.profile + ".json", 1, string); } }; var ControlAction = { - click: function () { - var control = getControl(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]); + mutedKey: false, + + timeoutDelay: function (text, time, stopfunc, arg) { + var currTime = 0, + endTime = getTickCount() + time; + + while (getTickCount() < endTime) { + if (typeof stopfunc === "function" && stopfunc(arg)) { + break; + } + + if (currTime !== Math.floor((endTime - getTickCount()) / 1000)) { + currTime = Math.floor((endTime - getTickCount()) / 1000); + + D2Bot.updateStatus(text + " (" + Math.max(currTime, 0) + "s)"); + } + + delay(10); + } + }, + + click: function (type, x, y, xsize, ysize, targetx, targety) { + var control = getControl(type, x, y, xsize, ysize); if (!control) { - print("control not found " + arguments[0] + " " + arguments[1] + " " + arguments[2]); + print("control not found " + type + " " + x + " " + y + " location " + getLocation()); + return false; } - //delay(clickdelay); - delay(200); - control.click(arguments[5], arguments[6]); + control.click(targetx, targety); return true; }, - setText: function () { - var control = getControl(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]); + setText: function (type, x, y, xsize, ysize, text) { + if (!text) { + return false; + } + + var currText, + control = getControl(type, x, y, xsize, ysize); if (!control) { return false; } - //delay(textdelay); - delay(200); - control.setText(arguments[5]); + 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; }, - getText: function () { - var control = getControl(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]); + getText: function (type, x, y, xsize, ysize) { + var control = getControl(type, x, y, xsize, ysize); if (!control) { return false; @@ -171,50 +549,257 @@ var ControlAction = { return control.getText(); }, - clickRealm: function () { - this.click(6, 264, 391, 272, 25); - this.click(4, 257, 500, 292, 160, 403, 350 + arguments[0] * 25); - this.click(6, 281, 538, 96, 32); + joinChannel: function (channel) { + me.blockMouse = true; + + var i, currChan, tick, + rval = false, + timeout = 5000; + +MainLoop: + while (true) { + switch (getLocation()) { + case 1: // Lobby + this.click(6, 27, 480, 120, 20); + + break; + case 3: // Chat + currChan = this.getText(4, 28, 138, 354, 60); // returns array + + if (currChan) { + for (i = 0; i < currChan.length; i += 1) { + if (currChan[i].split(" (") && currChan[i].split(" (")[0].toLowerCase() === channel.toLowerCase()) { + rval = true; + + break MainLoop; + } + } + } + + if (!tick) { + this.click(6, 535, 490, 80, 20); + + tick = getTickCount(); + } + + break; + case 7: // Channel + this.setText(1, 432, 162, 155, 20, channel); + this.click(6, 671, 433, 96, 32); + + break; + } + + if (getTickCount() - tick >= timeout) { + break MainLoop; + } + + delay(100); + } + + me.blockMouse = false; + + return rval; + }, + + createGame: function (name, pass, diff, delay) { + var control; + + ControlAction.setText(1, 432, 162, 158, 20, name); + ControlAction.setText(1, 432, 217, 158, 20, pass); + + switch (diff) { + case "Normal": + ControlAction.click(6, 430, 381, 16, 16); + + break; + 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); // Click Hell + + break; + } + + if (delay) { + this.timeoutDelay("Make Game Delay", delay); + } + + me.blockMouse = true; + + print("Creating Game: " + name); + ControlAction.click(6, 594, 433, 172, 32); + + me.blockMouse = false; + }, + + clickRealm: function (realm) { + if (realm < 0 || realm > 3) { + throw new Error("clickRealm: Invalid realm!"); + } + + var control, currentRealm; + + me.blockMouse = true; + +MainLoop: + while (true) { + switch (getLocation()) { + case 8: + control = getControl(6, 264, 391, 272, 25); + + if (control) { + switch (control.text.split(getLocaleString(11049).substring(0, getLocaleString(11049).length - 2))[1]) { + case "U.S. EAST": + currentRealm = 1; + + break; + case "U.S. WEST": + currentRealm = 0; + + break; + case "ASIA": + currentRealm = 2; + + break; + case "EUROPE": + currentRealm = 3; + + break; + } + } + + if (currentRealm === realm) { + break MainLoop; + } + + this.click(6, 264, 391, 272, 25); + + break; + case 27: + this.click(4, 257, 500, 292, 160, 403, 350 + realm * 25); + this.click(6, 281, 538, 96, 32); + + break; + } + + delay(500); + } + + me.blockMouse = false; + + return true; }, loginAccount: function (info) { - var realms = { - "uswest": 0, - "useast": 1, - "asia": 2, - "europe": 3 - }; + me.blockMouse = true; + + var tick, locTick, + realms = { + "uswest": 0, + "useast": 1, + "asia": 2, + "europe": 3 + }; + + tick = getTickCount(); - while (getLocation() !== 12 && getLocation() !== 42) { +MainLoop: + while (true) { switch (getLocation()) { + case 0: + break; case 8: // main menu - ControlAction.clickRealm(realms[info.realm]); - this.click(6, 264, 366, 272, 35); // OK + if (info.realm) { + ControlAction.clickRealm(realms[info.realm]); + } + + this.click(6, 264, 366, 272, 35); + break; case 9: // login screen this.setText(1, 322, 342, 162, 19, info.account); this.setText(1, 322, 396, 162, 19, info.password); this.click(6, 264, 484, 272, 35); // log in + break; - case 10: // login error - acc doesn't exist? TODO: handle all login errors - this.click(6, 335, 412, 128, 35); // OK + case 11: + case 13: // realm down + // Unable to connect, let the caller handle it. + me.blockMouse = false; + return false; + case 12: // char screen - break + break MainLoop; case 18: // splash this.click(2, 0, 599, 800, 600); + break; - default: + case 16: // please wait + case 21: // connecting + case 23: // char screen connecting break; + case 42: // empty char screen + // make sure we're not on connecting screen + locTick = getTickCount(); + + while (getTickCount() - locTick < 3000 && getLocation() === 42) { + delay(25); + } + + // char screen connecting + if (getLocation() === 23) { + break; + } + + break MainLoop; // break if we're sure we're on empty char screen + default: + print(getLocation()); + + me.blockMouse = false; + + return false; } - delay(500); + if (getTickCount() - tick >= 20000) { + return false; + } + + delay(100); } delay(1000); + me.blockMouse = false; + return getLocation() === 12 || getLocation() === 42; }, makeAccount: function (info) { + me.blockMouse = true; + var realms = { "uswest": 0, "useast": 1, @@ -227,24 +812,34 @@ var ControlAction = { case 8: // main menu ControlAction.clickRealm(realms[info.realm]); this.click(6, 264, 366, 272, 35); + break; case 9: // login screen this.click(6, 264, 572, 272, 35); + break; case 18: // splash this.click(2, 0, 599, 800, 600); + + break; + case 29: // Char create + this.click(6, 33, 572, 128, 35); + break; case 31: // ToU this.click(6, 525, 513, 128, 35); + break; case 32: // new account this.setText(1, 322, 342, 162, 19, info.account); this.setText(1, 322, 396, 162, 19, info.password); this.setText(1, 322, 450, 162, 19, info.password); this.click(6, 627, 572, 128, 35); + break; case 33: // please read this.click(6, 525, 513, 128, 35); + break; case 34: // e-mail if (getControl(6, 415, 412, 128, 35)) { @@ -258,14 +853,26 @@ var ControlAction = { break; } - delay(500); + delay(100); } + me.blockMouse = false; + return true; }, findCharacter: function (info) { - var control, text; + var control, text, tick; + + tick = getTickCount(); + + while (getLocation() !== 12) { + if (getTickCount() - tick >= 5000) { + break; + } + + delay(25); + } if (getLocation() === 12) { control = getControl(4, 37, 178, 200, 92); @@ -284,7 +891,53 @@ var ControlAction = { return false; }, + // get all characters + getCharacters: function () { + var control, text, + list = []; + + if (getLocation() === 12) { + control = getControl(4, 37, 178, 200, 92); + + if (control) { + do { + text = control.getText(); + + if (text instanceof Array && typeof text[1] === "string") { + list.push(text[1]); + } + } while (control.getNext()); + } + } + + return list; + }, + + // get character position + getPosition: function () { + var control, text, + position = 0; + + if (getLocation() === 12) { + control = getControl(4, 37, 178, 200, 92); + + if (control) { + do { + text = control.getText(); + + if (text instanceof Array && typeof text[1] === "string") { + position += 1; + } + } while (control.getNext()); + } + } + + return position; + }, + loginCharacter: function (info) { + me.blockMouse = true; + var control, text; while (getLocation() !== 1) { // cycle until in lobby @@ -296,7 +949,7 @@ var ControlAction = { do { text = control.getText(); - if (text instanceof Array && typeof text[1] === "string" && text[1] === info.charName) { + if (text instanceof Array && typeof text[1] === "string" && text[1].toLowerCase() === info.charName.toLowerCase()) { control.click(); this.click(6, 627, 572, 128, 35); @@ -308,52 +961,79 @@ var ControlAction = { break; case 42: // empty character select this.click(6, 33, 572, 128, 35); + break; + case 14: // disconnected? + case 30: // player not found? + me.blockMouse = false; + + return false; default: break; } - delay(500); + delay(100); } + me.blockMouse = false; + return true; }, makeCharacter: function (info) { + me.blockMouse = true; + if (!info.charClass) { 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; case 29: // select character switch (info.charClass) { case "barbarian": clickCoords = [400, 280]; + break; case "amazon": clickCoords = [100, 280]; + break; case "necromancer": clickCoords = [300, 290]; + break; case "sorceress": clickCoords = [620, 270]; + break; case "assassin": clickCoords = [200, 280]; + break; case "druid": clickCoords = [700, 280]; + break; case "paladin": clickCoords = [521, 260]; + break; } @@ -371,22 +1051,34 @@ var ControlAction = { break; case 15: // new character - this.setText(1, 318, 510, 157, 16, info.charName); + if (getControl(6, 421, 337, 96, 32)) { // hardcore char warning + this.click(6, 421, 337, 96, 32); + } else { + this.setText(1, 318, 510, 157, 16, info.charName); - if (!this.expansion) { - this.click(6, 319, 540, 15, 16); - } + if (!info.expansion) { + this.click(6, 319, 540, 15, 16); + } - if (!info.ladder) { - this.click(6, 319, 580, 15, 16); - } + if (!info.ladder) { + this.click(6, 319, 580, 15, 16); + } + + if (info.hardcore) { + this.click(6, 319, 560, 15, 16); + } - if (info.hardcore) { - this.click(6, 319, 560, 15, 16); + this.click(6, 627, 572, 128, 35); } - this.click(6, 627, 572, 128, 35); break; + case 30: // char name exists (text box 4, 268, 320, 264, 120) + ControlAction.click(6, 351, 337, 96, 32); + ControlAction.click(6, 33, 572, 128, 35); + + me.blockMouse = false; + + return false; default: break; } @@ -394,26 +1086,77 @@ var ControlAction = { delay(500); } + me.blockMouse = false; + return true; + }, + + // Test version - modified core only + getGameList: function () { + var i, text, gameList; + + text = this.getText(4, 432, 393, 160, 173); + + if (text) { + gameList = []; + + for (i = 0; i < text.length; i += 1) { + gameList.push({ + gameName: text[i][0], + players: text[i][1] + }); + } + + return gameList; + } + + return false; } }; var ShitList = { - read: function () { - var obj, string; - - if (!FileTools.exists("shitlist.json")) { + create: function () { + var string, obj = { shitlist: [] }; - string = JSON.stringify(obj); + string = JSON.stringify(obj); + + //FileTools.writeText("shitlist.json", string); + Misc.fileAction("shitlist.json", 1, string); - FileTools.writeText("shitlist.json", string); + return obj; + }, + + getObj: function () { + var obj, + //string = FileTools.readText("shitlist.json"); + string = Misc.fileAction("shitlist.json", 0); + + try { + obj = JSON.parse(string); + } catch (e) { + obj = this.create(); + } + + if (obj) { + return obj; + } + + print("Failed to read ShitList. Using null values"); + + return {shitlist: []}; + }, + + read: function () { + var obj; + + if (!FileTools.exists("shitlist.json")) { + this.create(); } - string = FileTools.readText("shitlist.json"); - obj = JSON.parse(string); + obj = this.getObj(); return obj.shitlist; }, @@ -421,13 +1164,13 @@ var ShitList = { add: function (name) { var obj, string; - string = FileTools.readText("shitlist.json"); - obj = JSON.parse(string); + obj = this.getObj(); obj.shitlist.push(name); string = JSON.stringify(obj); - FileTools.writeText("shitlist.json", string); + //FileTools.writeText("shitlist.json", string); + Misc.fileAction("shitlist.json", 1, string); } }; \ No newline at end of file diff --git a/d2bs/kolbot/libs/TorchSystem.js b/d2bs/kolbot/libs/TorchSystem.js new file mode 100644 index 000000000..e51e56bdd --- /dev/null +++ b/d2bs/kolbot/libs/TorchSystem.js @@ -0,0 +1,342 @@ +/** +* @filename TorchSystem.js +* @author kolton +* @desc Works in conjunction with OrgTorch script. Allows the uber killer to get keys from other profiles. +*/ + +var TorchSystem = { + LogKeys: false, + LogOrgans: true, + + FarmerProfiles: { +// ############################ S E T U P ########################################## + + /* Each uber killer profile can have their own army of key finders + Multiple entries are separated with a comma + Example config: + + "Farmer 1": { // Farmer profile name + // Put key finder profiles here. Example - KeyFinderProfiles: ["MF 1", "MF 2"], + KeyFinderProfiles: ["mf 1", "mf 2"], + + // Put the game name of uber killer here (without numbers). Key finders will join this game to drop keys. Example - FarmGame: "Ubers-", + FarmGame: "torch1-" + }, + + "Farmer 2": { // Farmer profile name + // Put key finder profiles here. Example - KeyFinderProfiles: ["MF 1", "MF 2"], + KeyFinderProfiles: ["mf 3", "mf 4"], + + // Put the game name of uber killer here (without numbers). Key finders will join this game to drop keys. Example - FarmGame: "Ubers-", + FarmGame: "torch2-" + } + */ + + // Edit here! + + "PROFILE NAME": { // Farmer profile name + // Put key finder profiles here. Example - KeyFinderProfiles: ["MF 1", "MF 2"], + KeyFinderProfiles: [""], + + // Put the game name of uber killer here (without numbers). Key finders will join this game to drop keys. Example - FarmGame: "Ubers-", + FarmGame: "" + } + +// ################################################################################# + }, + + // Don't touch + inGame: false, + check: false, + + getFarmers: function () { + var i, j, + list = []; + + for (i in this.FarmerProfiles) { + if (this.FarmerProfiles.hasOwnProperty(i)) { + for (j = 0; j < this.FarmerProfiles[i].KeyFinderProfiles.length; j += 1) { + if (this.FarmerProfiles[i].KeyFinderProfiles[j].toLowerCase() === me.profile.toLowerCase()) { + this.FarmerProfiles[i].profile = i; + + list.push(this.FarmerProfiles[i]); + } + } + } + } + + if (list.length) { + return list; + } + + return false; + }, + + isFarmer: function () { + if (this.FarmerProfiles.hasOwnProperty(me.profile)) { + this.FarmerProfiles[me.profile].profile = me.profile; + + return this.FarmerProfiles[me.profile]; + } + + return false; + }, + + /*inGameCheck: function () { + var i, j, farmers, dropArray, item, + keyIds = ["pk1", "pk2", "pk3"]; + + farmers = this.getFarmers(); + + if (!farmers) { + return false; + } + + for (i = 0; i < farmers.length; i += 1) { + if (farmers[i].FarmGame.length > 0 && me.gamename.toLowerCase().match(farmers[i].FarmGame.toLowerCase())) { + print("ÿc4Torch Systemÿc0: In Farm game."); + D2Bot.printToConsole("Torch System: In Farm game.", 7); + Town.goToTown(1); + + if (!Town.openStash()) { + return false; + } + + while (true) { + // Reset array + dropArray = []; + + // Search for one of each key and put them in drop array + for (j = 0; j < 3; j += 1) { + // Find a key (one type per cycle) + item = me.getItem(keyIds[j]); + + // Build an array of keys to drop + if (item) { + dropArray.push(copyUnit(item)); + } + } + + // Abort if there's no complete sets of keys + if (dropArray.length !== 3) { + break; + } + + // Drop a keyset + for (j = 0; j < 3; j += 1) { + dropArray[j].drop(); + } + } + + delay(5000); + quit(); + delay(10000); + + return true; + } + } + + return false; + },*/ + + inGameCheck: function () { + var i, j, neededItems, + farmers = this.getFarmers(); + + if (!farmers) { + return false; + } + + for (i = 0; i < farmers.length; i += 1) { + if (farmers[i].FarmGame.length > 0 && me.gamename.toLowerCase().match(farmers[i].FarmGame.toLowerCase())) { + print("ÿc4Torch Systemÿc0: In Farm game."); + D2Bot.printToConsole("Torch System: Transfering keys.", 7); + D2Bot.updateStatus("Torch System: In game."); + Town.goToTown(1); + + if (Town.openStash()) { + neededItems = this.keyCheck(); + + if (neededItems) { + for (i in neededItems) { + if (neededItems.hasOwnProperty(i)) { + while (neededItems[i].length) { + neededItems[i].shift().drop(); + } + } + } + } + } + + if (me.getStat(Stats.gold) >= 100000) { + gold(100000); + } + + delay(5000); + quit(); + //delay(10000); + + return true; + } + } + + return false; + }, + + keyCheck: function () { + var i, + neededItems = {}, + farmers = this.getFarmers(); + + if (!farmers) { + return false; + } + + function keyCheckEvent(mode, msg) { + var i, j, obj, item; + + if (mode === 6) { + obj = JSON.parse(msg); + + if (obj.name === "neededItems") { + for (i in obj.value) { + if (obj.value.hasOwnProperty(i) && obj.value[i] > 0) { + switch (i) { + case "pk1": + case "pk2": + case "pk3": + item = me.getItem(i); + + if (item) { + do { + if (!neededItems[i]) { + neededItems[i] = []; + } + + neededItems[i].push(copyUnit(item)); + + if (neededItems[i].length >= obj.value[i]) { + break; + } + } while (item.getNext()); + } + + break; + case "rv": + item = me.getItem(); + + if (item) { + do { + if (item.code === "rvs" || item.code === "rvl") { + if (!neededItems[i]) { + neededItems[i] = []; + } + + neededItems[i].push(copyUnit(item)); + + if (neededItems[i].length >= Math.min(2, obj.value[i])) { + break; + } + } + } while (item.getNext()); + } + + break; + } + } + } + } + } + } + + addEventListener("copydata", keyCheckEvent); + + // TODO: one mfer for multiple farmers handling + for (i = 0; i < farmers.length; i += 1) { + sendCopyData(null, farmers[i].profile, 6, JSON.stringify({name: "keyCheck", profile: me.profile})); + delay(250); + + if (neededItems.hasOwnProperty("pk1") || neededItems.hasOwnProperty("pk2") || neededItems.hasOwnProperty("pk3")) { + removeEventListener("copydata", keyCheckEvent); + + return neededItems; + } + } + + removeEventListener("copydata", keyCheckEvent); + + return false; + }, + + outOfGameCheck: function () { + if (!this.check) { + return false; + } + + this.check = false; + + var i, game, farmers; + + function CheckEvent(mode, msg) { + var i, obj, + farmers = TorchSystem.getFarmers(); + + if (mode === 6) { + obj = JSON.parse(msg); + + if (obj && obj.name === "gameName") { + for (i = 0; i < farmers.length; i += 1) { + if (obj.value.gameName.toLowerCase().match(farmers[i].FarmGame.toLowerCase())) { + game = [obj.value.gameName, obj.value.password]; + } + } + } + } + + return true; + } + + farmers = this.getFarmers(); + + if (!farmers) { + return false; + } + + addEventListener('copydata', CheckEvent); + + for (i = 0; i < farmers.length; i += 1) { + sendCopyData(null, farmers[i].profile, 6, JSON.stringify({name: "gameCheck", profile: me.profile})); + delay(500); + + if (game) { + break; + } + } + + removeEventListener('copydata', CheckEvent); + + if (game) { + //D2Bot.printToConsole("Joining key drop game.", 7); + delay(2000); + + this.inGame = true; + me.blockMouse = true; + + joinGame(game[0], game[1]); + + me.blockMouse = false; + + delay(5000); + + while (me.ingame) { + delay(1000); + } + + this.inGame = false; + + return true; + } + + return false; + } +}; \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/Abaddon.js b/d2bs/kolbot/libs/bots/Abaddon.js index 39cbf913f..be3d02cf0 100644 --- a/d2bs/kolbot/libs/bots/Abaddon.js +++ b/d2bs/kolbot/libs/bots/Abaddon.js @@ -6,10 +6,10 @@ function Abaddon() { Town.doChores(); - Pather.useWaypoint(111); + Pather.useWaypoint(Areas.Act5.Frigid_Highlands); Precast.doPrecast(true); - if (!Pather.moveToPreset(111, 2, 60) || !Pather.usePortal(125)) { + if (!Pather.moveToPreset(Areas.Act5.Frigid_Highlands, UnitType.Object, UniqueObjectIds.Permanent_Town_Portal) || !Pather.usePortal(Areas.Act5.Abaddon)) { throw new Error("Failed to move to Abaddon"); } diff --git a/d2bs/kolbot/libs/bots/AncientTunnels.js b/d2bs/kolbot/libs/bots/AncientTunnels.js index a6c3a5482..8e763b7f7 100644 --- a/d2bs/kolbot/libs/bots/AncientTunnels.js +++ b/d2bs/kolbot/libs/bots/AncientTunnels.js @@ -6,10 +6,18 @@ function AncientTunnels() { Town.doChores(); - Pather.useWaypoint(44); + Pather.useWaypoint(Areas.Act2.Lost_City); Precast.doPrecast(true); - if (!Pather.moveToExit(65, true)) { + if (Config.AncientTunnels.OpenChest && Pather.moveToPreset(me.area, UnitType.Object, 580) && Misc.openChests(5)) { + Pickit.pickItems(); + } + + if (Config.AncientTunnels.KillDarkElder && getPresetUnit(me.area, UnitType.NPC, SuperUniques.Dark_Elder) && Pather.moveToPreset(me.area, UnitType.NPC, SuperUniques.Dark_Elder)) { + Attack.clear(15, 0, getLocaleString(2886)); + } + + if (!Pather.moveToExit(Areas.Act2.Ancient_Tunnels, true)) { throw new Error("Failed to move to Ancient Tunnels"); } diff --git a/d2bs/kolbot/libs/bots/Andariel.js b/d2bs/kolbot/libs/bots/Andariel.js index bb7ddbca7..99f169880 100644 --- a/d2bs/kolbot/libs/bots/Andariel.js +++ b/d2bs/kolbot/libs/bots/Andariel.js @@ -5,16 +5,50 @@ */ function Andariel() { + this.killAndariel = function () { + var i, + target = getUnit(UnitType.NPC, UnitClassID.andariel); + + if (!target) { + throw new Error("Andariel not found."); + } + + if (Config.MFLeader) { + Pather.makePortal(); + say("kill " + UnitClassID.andariel); + } + + 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(me.x > 22548 ? 22535 : 22560, 9520); + } + } + + return target.dead; + }; + Town.doChores(); - Pather.useWaypoint(35); + Pather.useWaypoint(Areas.Act1.Catacombs_Level_2); Precast.doPrecast(true); - if (!Pather.moveToExit([36, 37], true)) { + if (!Pather.moveToExit([Areas.Act1.Catacombs_Level_3, Areas.Act1.Catacombs_Level_4], true)) { throw new Error("Failed to move to Catacombs Level 4"); } - Pather.moveTo(22561, 9578); - Attack.kill(156); // Andariel + Pather.moveTo(22549, 9520); + + if (me.classid === ClassID.Sorceress && me.gametype === GameType.Classic) { + this.killAndariel(); + } else { + Attack.kill(UnitClassID.andariel); // Andariel + } + delay(2000); // Wait for minions to die. Pickit.pickItems(); diff --git a/d2bs/kolbot/libs/bots/AutoBaal.js b/d2bs/kolbot/libs/bots/AutoBaal.js index a2403a148..e3a6fb425 100644 --- a/d2bs/kolbot/libs/bots/AutoBaal.js +++ b/d2bs/kolbot/libs/bots/AutoBaal.js @@ -1,5 +1,5 @@ /** -* @filename Andariel.js +* @filename AutoBaal.js * @author kolton * @desc Universal Baal leecher by Kolton with Autoleader by Ethic * Pure leech script for throne and Baal @@ -9,11 +9,11 @@ function AutoBaal() { // editable variables - var safeMsg = ["safe", "throne clear", "leechers can come", "tp is up", "1 clear"], // safe message - casing doesn't matter - baalMsg = ["baal", "submortal"], // baal message - casing doesn't matter - hotMsg = ["hot"], // used for shrine hunt - // internal variables - i, baalCheck, throneCheck, hotCheck, leader, suspect, solofail, portal, baal; + var i, baalCheck, throneCheck, hotCheck, leader, suspect, solofail, portal, baal, + // internal variables + safeMsg = ["safe", "throne clear", "leechers can come", "tp is up", "1 clear"], // safe message - casing doesn't matter + baalMsg = ["baal"], // baal message - casing doesn't matter + hotMsg = ["hot", "warm", "dangerous", "lethal"]; // used for shrine hunt addEventListener('chatmsg', // chat event, listen to what leader says function (nick, msg) { // handler function @@ -21,8 +21,9 @@ function AutoBaal() { if (nick === leader) { // filter leader messages for (i = 0; i < hotMsg.length; i += 1) { // loop through all predefined messages to find a match - if (msg.toLowerCase().indexOf(hotMsg[i].toLowerCase()) > -1) { // leader says a hot tp message + if (msg.toLowerCase().indexOf(hotMsg[i].toLowerCase()) > -1 && Config.AutoBaal.FindShrine === 1) { // leader says a hot tp message hotCheck = true; // safe to enter baal chamber + break; } } @@ -30,6 +31,7 @@ function AutoBaal() { for (i = 0; i < safeMsg.length; i += 1) { // loop through all predefined messages to find a match if (msg.toLowerCase().indexOf(safeMsg[i].toLowerCase()) > -1) { // leader says a safe tp message throneCheck = true; // safe to enter throne + break; } } @@ -37,14 +39,93 @@ function AutoBaal() { for (i = 0; i < baalMsg.length; i += 1) { // loop through all predefined messages to find a match if (msg.toLowerCase().indexOf(baalMsg[i].toLowerCase()) > -1) { // leader says a baal message baalCheck = true; // safe to enter baal chamber + break; } } } + }); + + // test + this.longRangeSupport = function () { + var monster, monList, index; + + switch (me.classid) { + case ClassID.Amazon: + break; + case ClassID.Sorceress: + break; + case ClassID.Necromancer: + ClassAttack.raiseArmy(50); + + if (Config.Curse[1] > 0) { + monster = getUnit(UnitType.NPC); + + if (monster) { + do { + if (Attack.checkMonster(monster) && getDistance(me, monster) < 50 && !checkCollision(me, monster, 0x4) && + ClassAttack.isCursable(monster) && !(monster.spectype & 0x7) && !monster.getState(ClassAttack.curseState[1])) { + Skill.cast(Config.Curse[1], 0, monster); + } + } while (monster.getNext()); + } + } + + break; + case ClassID.Paladin: + break; + case ClassID.Barbarian: + break; + case ClassID.Druid: + break; + case ClassID.Assassin: + break; + } + + if ([Skills.Amazon.Charged_Strike, Skills.Sorceress.Lightning, Skills.Sorceress.Fire_Wall, Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard, + Skills.Necromancer.Bone_Spear, Skills.Necromancer.Bone_Spirit, Skills.Barbarian.Double_Throw, Skills.Druid.Volcano].indexOf(Config.AttackSkill[1]) === -1 && + [Skills.Amazon.Charged_Strike, Skills.Sorceress.Lightning, Skills.Sorceress.Fire_Wall, Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard, + Skills.Necromancer.Bone_Spear, Skills.Necromancer.Bone_Spirit, Skills.Barbarian.Double_Throw, Skills.Druid.Volcano].indexOf(Config.AttackSkill[3]) === -1) { + return false; + } + + monster = getUnit(UnitType.NPC); + monList = []; + + if (monster) { + do { + if (Attack.checkMonster(monster) && getDistance(me, monster) < 50 && !checkCollision(me, monster, 0x4)) { + monList.push(copyUnit(monster)); + } + } while (monster.getNext()); + } + + while (monList.length) { + monList.sort(Sort.units); + + monster = copyUnit(monList[0]); + + if (monster && Attack.checkMonster(monster)) { + index = monster.spectype & 0x7 ? 1 : 3; + + if (Attack.checkResist(monster, Attack.getSkillElement(Config.AttackSkill[index]))) { + if (Config.AttackSkill[index] > -1) { + ClassAttack.doCast(monster, Config.AttackSkill[index], Config.AttackSkill[index + 1]); + } + } else { + monList.shift(); + } + } else { + monList.shift(); + } + + delay(5); } - ); - function AutoLeaderDetect(destination) { // autoleader by Ethic + return true; + }; + + function autoLeaderDetect(destination) { // autoleader by Ethic do { solofail = 0; suspect = getParty(); // get party object (players in game) @@ -59,7 +140,7 @@ function AutoBaal() { print("ÿc4AutoBaal: ÿc0Autodetected " + leader); return true; } - } while (suspect.getNext()); + } while (suspect.getNext()); if (solofail === 0) { // empty game, nothing left to do return false; @@ -75,26 +156,47 @@ function AutoBaal() { throw new Error("Town.goToTown failed."); // critical error - can't reach harrogath } + if (Config.Leader) { + leader = Config.Leader; + + for (i = 0; i < 30; i += 1) { + if (Misc.inMyParty(leader)) { + break; + } + + delay(1000); + } + + if (i === 30) { + throw new Error("Autobaal: Leader not partied"); + } + } + + if (Config.AutoBaal.FindShrine === 2) { + hotCheck = true; + } + Town.doChores(); Town.move("portalspot"); - if (AutoLeaderDetect(131)) { // find the first player in area 131 - throne of destruction + if (leader || autoLeaderDetect(Areas.Act5.Throne_Of_Destruction)) { // find the first player in area 131 - throne of destruction while (Misc.inMyParty(leader)) { // do our stuff while partied - if (hotCheck && Config.AutoBaal.FindShrine) { - Pather.useWaypoint(4); + if (hotCheck) { + Pather.useWaypoint(Areas.Act1.Stony_Field); + Precast.doPrecast(true); - for (i = 4; i > 1; i -= 1) { - if (Misc.getShrinesInArea(i, 15)) { + for (i = Areas.Act1.Stony_Field; i > Areas.Act1.Rogue_Encampment; i -= 1) { + if (Misc.getShrinesInArea(i, 15, true)) { break; } } if (i === 1) { Town.goToTown(); - Pather.useWaypoint(5); + Pather.useWaypoint(Areas.Act1.Dark_Wood); - for (i = 5; i < 8; i += 1) { - if (Misc.getShrinesInArea(i, 15)) { + for (i = Areas.Act1.Dark_Wood; i < Areas.Act1.Den_Of_Evil; i += 1) { + if (Misc.getShrinesInArea(i, 15, true)) { break; } } @@ -106,26 +208,29 @@ function AutoBaal() { hotCheck = false; } - if (throneCheck && me.area === 109) { // wait for throne signal - leader's safe message + if (throneCheck && me.area === Areas.Act5.Harrogath) { // wait for throne signal - leader's safe message print("ÿc4AutoBaal: ÿc0Trying to take TP to throne."); - Pather.usePortal(131, leader); // take TP to throne - delay(500); - Pather.moveTo(15113, 5050); // move to a safe spot + Pather.usePortal(Areas.Act5.Throne_Of_Destruction, null); // take TP to throne + Pather.moveTo(Config.AutoBaal.LeechSpot[0], Config.AutoBaal.LeechSpot[1]); // move to a safe spot Precast.doPrecast(true); Town.getCorpse(); // check for corpse - happens if you die and reenter } - if (baalCheck && me.area === 131) { // wait for baal signal - leader's baal message + if (!baalCheck && me.area === Areas.Act5.Throne_Of_Destruction && Config.AutoBaal.LongRangeSupport) { + this.longRangeSupport(); + } + + if (baalCheck && me.area === Areas.Act5.Throne_Of_Destruction) { // wait for baal signal - leader's baal message Pather.moveTo(15092, 5010); // move closer to chamber portal - Precast.doPrecast(true); + Precast.doPrecast(false); - while (getUnit(1, 543)) { // wait for baal to go through the portal + while (getUnit(UnitType.NPC, UnitClassID.baalthrone)) { // wait for baal to go through the portal delay(500); } - portal = getUnit(2, 563); + portal = getUnit(UnitType.Object, UniqueObjectIds.Worldstone_Chamber); - delay(5000); // wait for others to enter first - helps with curses and tentacles from spawning around you + delay(2000); // wait for others to enter first - helps with curses and tentacles from spawning around you print("ÿc4AutoBaal: ÿc0Entering chamber."); if (Pather.usePortal(null, null, portal)) { // enter chamber @@ -135,13 +240,17 @@ function AutoBaal() { Town.getCorpse(); // check for corpse - happens if you die and reenter } - baal = getUnit(1, 544); + baal = getUnit(UnitType.NPC, UnitClassID.baalcrab); - if (baal && (baal.mode === 0 || baal.mode === 12)) { - break; + if (baal) { + if (baal.mode === NPCModes.death || baal.mode === NPCModes.dead) { + break; + } + + this.longRangeSupport(); } - if (me.mode === 17) { // death check + if (me.mode === PlayerModes.Dead) { // death check me.revive(); // revive if dead } diff --git a/d2bs/kolbot/libs/bots/Baal.js b/d2bs/kolbot/libs/bots/Baal.js index 67b719219..d4a7ddc04 100644 --- a/d2bs/kolbot/libs/bots/Baal.js +++ b/d2bs/kolbot/libs/bots/Baal.js @@ -1,61 +1,64 @@ /** -* @filename Baal.js -* @author kolton -* @desc clear Throne of Destruction and kill Baal -*/ + * @filename Baal.js + * @author kolton, modified by YGM + * @desc clear Throne of Destruction and kill Baal + */ function Baal() { - var tick, portal; + var portal, tick; this.preattack = function () { var check; switch (me.classid) { - case 1: - if ([56, 59, 64].indexOf(Config.AttackSkill[1]) > -1) { - if (me.getState(121)) { - delay(500); + case ClassID.Sorceress: // Sorceress + switch (Config.AttackSkill[3]) { + case Skills.Sorceress.Lightning: + case Skills.Sorceress.Chain_Lightning: + case Skills.Sorceress.Meteor: + case Skills.Sorceress.Blizzard: + case Skills.Sorceress.Frozen_Orb: + if (me.getState(States.SKILLDELAY)) { + while (me.getState(States.SKILLDELAY)) { + delay(100); + } } else { - Skill.cast(Config.AttackSkill[1], 0, 15093, 5024); + return Skill.cast(Config.AttackSkill[1], 0, 15094 + rand(-1, 1), 5028); } - } - return true; - case 3: // Paladin - if (Config.AttackSkill[3] !== 112) { - return false; + break; } - if (getDistance(me, 15093, 5029) > 3) { - Pather.moveTo(15093, 5029); - } + break; + case ClassID.Paladin: // Paladin + if (Config.AttackSkill[3] === Skills.Paladin.Blessed_Hammer) { + if (Config.AttackSkill[4] > 0) { + Skill.setSkill(Config.AttackSkill[4], 0); + } - if (Config.AttackSkill[4] > 0) { - Skill.setSkill(Config.AttackSkill[4], 0); + return Skill.cast(Config.AttackSkill[3], 1); } - Skill.cast(Config.AttackSkill[3], 1); - - return true; - case 5: // Druid - if (Config.AttackSkill[3] === 245) { - Skill.cast(Config.AttackSkill[3], 0, 15093, 5029); - - return true; + break; + case ClassID.Druid: // Druid + if (Config.AttackSkill[3] === Skills.Druid.Tornado) { + return Skill.cast(Config.AttackSkill[3], 0, 15094 + rand(-1, 1), 5028); } break; - case 6: // Assassin + case ClassID.Assassin: // Assassin if (Config.UseTraps) { - check = ClassAttack.checkTraps({x: 15093, y: 5029}); + check = ClassAttack.checkTraps({x: 15094, y: 5028}); if (check) { - ClassAttack.placeTraps({x: 15093, y: 5029}, 5); - - return true; + return ClassAttack.placeTraps({x: 15094, y: 5028}, 5); } } + if (Config.AttackSkill[3] === Skills.Assassin.Shock_Field) { // shock-web + return Skill.cast(Config.AttackSkill[3], 0, 15094, 5028); + } + break; } @@ -63,23 +66,23 @@ function Baal() { }; this.checkThrone = function () { - var monster = getUnit(1); + var monster = getUnit(UnitType.NPC); if (monster) { do { if (Attack.checkMonster(monster) && monster.y < 5080) { switch (monster.classid) { - case 23: - case 62: + case UnitClassID.fallen5: + case UnitClassID.fallenshaman5: return 1; - case 105: - case 381: + case UnitClassID.unraveler5: + case UnitClassID.skmage_cold3: return 2; - case 557: + case UnitClassID.baalhighpriest: return 3; - case 558: + case UnitClassID.venomlord: return 4; - case 571: + case UnitClassID.baalminion1: return 5; default: Attack.getIntoPosition(monster, 10, 0x4); @@ -97,10 +100,10 @@ function Baal() { this.clearThrone = function () { var i, monster, monList = [], - pos = [15097, 5054, 15085, 5053, 15085, 5040, 15098, 5040, 15099, 5022, 15086, 5024]; + pos = [15094, 5022, 15094, 5041, 15094, 5060, 15094, 5041, 15094, 5022]; if (Config.AvoidDolls) { - monster = getUnit(1, 691); + monster = getUnit(UnitType.NPC, UnitClassID.bonefetish7); if (monster) { do { @@ -117,21 +120,18 @@ function Baal() { for (i = 0; i < pos.length; i += 2) { Pather.moveTo(pos[i], pos[i + 1]); - Attack.clear(30); + Attack.clear(25); } }; this.checkHydra = function () { - var monster = getUnit(1, "hydra"); - + var monster = getUnit(UnitType.NPC, "hydra"); if (monster) { do { - if (monster.mode !== 12 && monster.getStat(172) !== 2) { - Pather.moveTo(15118, 5002); - - while (monster.mode !== 12) { + if (monster.mode !== NPCModes.dead && monster.getStat(Stats.alignment) !== 2) { + Pather.moveTo(15072, 5002); + while (monster.mode !== NPCModes.dead) { delay(500); - if (!copyUnit(monster).x) { break; } @@ -145,44 +145,111 @@ function Baal() { return true; }; + this.announce = function () { + var count, string, souls, dolls, + monster = getUnit(UnitType.NPC); + + if (monster) { + count = 0; + + do { + if (Attack.checkMonster(monster) && monster.y < 5094) { + if (getDistance(me, monster) <= 40) { + count += 1; + } + + if (!souls && monster.classid === UnitClassID.willowisp7) { + souls = true; + } + + if (!dolls && monster.classid === UnitClassID.bonefetish7) { + dolls = true; + } + } + } while (monster.getNext()); + } + + if (count > 30) { + string = "DEADLY!!!" + " " + count + " monster" + (count > 1 ? "s " : " ") + "nearby."; + } else if (count > 20) { + string = "Lethal!" + " " + count + " monster" + (count > 1 ? "s " : " ") + "nearby."; + } else if (count > 10) { + string = "Dangerous!" + " " + count + " monster" + (count > 1 ? "s " : " ") + "nearby."; + } else if (count > 0) { + string = "Warm" + " " + count + " monster" + (count > 1 ? "s " : " ") + "nearby."; + } else { + string = "Cool TP. No immediate monsters."; + } + + if (souls) { + string += " Souls "; + + if (dolls) { + string += "and Dolls "; + } + + string += "in area."; + } else if (dolls) { + string += " Dolls in area."; + } + + say(string); + }; + Town.doChores(); - Pather.useWaypoint(129); + Pather.useWaypoint(Config.RandomPrecast ? "random" : Areas.Act5.The_Worldstone_Keep_Level_2); Precast.doPrecast(true); - if (!Pather.moveToExit([130, 131], true)) { + if (me.area !== Areas.Act5.The_Worldstone_Keep_Level_2) { + Pather.useWaypoint(Areas.Act5.The_Worldstone_Keep_Level_2); + } + + if (!Pather.moveToExit([Areas.Act5.The_Worldstone_Keep_Level_3, Areas.Act5.Throne_Of_Destruction], true)) { throw new Error("Failed to move to Throne of Destruction."); } - Pather.moveTo(15113, 5040); + Pather.moveTo(15095, 5029); - if (Config.PublicMode) { - Pather.makePortal(); - say(Config.Baal.HotTPMsg); + if (Config.Baal.DollQuit && getUnit(UnitType.NPC, UnitClassID.bonefetish7)) { + say("Dolls found! NG."); + + return true; } - if (Config.Baal.DollQuit && getUnit(1, 691)) { - print("Soul Killers found."); + if (Config.Baal.SoulQuit && getUnit(UnitType.NPC, UnitClassID.willowisp7)) { + say("Souls found! NG."); return true; } - Attack.clear(15); + if (Config.PublicMode) { + this.announce(); + Pather.moveTo(15118, 5002); + Pather.makePortal(); + say(Config.Baal.HotTPMessage); + Attack.clear(15); + } + this.clearThrone(); if (Config.PublicMode) { - say(Config.Baal.SafeTPMsg); + Pather.moveTo(15118, 5045); + Pather.makePortal(); + say(Config.Baal.SafeTPMessage); + Precast.doPrecast(true); } tick = getTickCount(); - Pather.moveTo(15093, me.classid === 3 ? 5029 : 5039); + + Pather.moveTo(15094, me.classid === ClassID.Paladin ? 5029 : 5038); MainLoop: while (true) { - if (getDistance(me, 15093, me.classid === 3 ? 5029 : 5039) > 3) { - Pather.moveTo(15093, me.classid === 3 ? 5029 : 5039); + if (getDistance(me, 15094, me.classid === ClassID.Paladin ? 5029 : 5038) > 3) { + Pather.moveTo(15094, me.classid === ClassID.Paladin ? 5029 : 5038); } - if (!getUnit(1, 543)) { + if (!getUnit(UnitType.NPC, UnitClassID.baalthrone)) { break MainLoop; } @@ -220,8 +287,8 @@ MainLoop: break MainLoop; default: if (getTickCount() - tick < 7e3) { - if (me.getState(2)) { - Skill.setSkill(109, 0); + if (me.getState(States.POISON)) { + Skill.setSkill(Skills.Paladin.Cleansing, 0); } break; @@ -234,34 +301,34 @@ MainLoop: break; } - Precast.doPrecast(false); delay(10); } - Pather.moveTo(15092, 5011); - Precast.doPrecast(true); + if (Config.Baal.KillBaal) { + if (Config.PublicMode) { + say(Config.Baal.BaalMessage); + } - while (getUnit(1, 543)) { - delay(500); - } + Pather.moveTo(15090, 5008); + delay(5000); + Precast.doPrecast(true); - if (Config.PublicMode) { - say(Config.Baal.BaalMsg); - } + while (getUnit(UnitType.NPC, UnitClassID.baalthrone)) { + delay(500); + } - delay(1000); + portal = getUnit(UnitType.Object, UniqueObjectIds.Worldstone_Chamber); - portal = getUnit(2, 563); + if (portal) { + Pather.usePortal(null, null, portal); + } else { + throw new Error("Couldn't find portal."); + } - if (portal) { - Pather.usePortal(null, null, portal); - } else { - throw new Error("Couldn't find portal."); + Pather.moveTo(15134, 5923); + Attack.kill(UnitClassID.baalcrab); // Baal + Pickit.pickItems(); } - Pather.moveTo(15134, 5923); - Attack.kill(544); // Baal - Pickit.pickItems(); - return true; } \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/BaalAssistant.js b/d2bs/kolbot/libs/bots/BaalAssistant.js new file mode 100644 index 000000000..5f9c57db9 --- /dev/null +++ b/d2bs/kolbot/libs/bots/BaalAssistant.js @@ -0,0 +1,682 @@ +/** + * @filename BaalAssistant.js + * @author kolton, modified by YGM + * @desc Help or Leech Baal Runs. + */ + +function BaalAssistant() { + + var Leader = Config.Leader, // Not entriely needed in the configs. + KillNihlathak = Config.BaalAssistant.KillNihlathak, + FastChaos = Config.BaalAssistant.FastChaos, + Wait = Config.BaalAssistant.Wait, // Not entriely needed in the configs. + Helper = Config.BaalAssistant.Helper, + GetShrine = Config.BaalAssistant.GetShrine, + GetShrineWaitForHotTP = Config.BaalAssistant.GetShrineWaitForHotTP, + RandomPrecast = Config.RandomPrecast, // Not entriely needed in the configs. + SkipTP = Config.BaalAssistant.SkipTP, + WaitForSafeTP = Config.BaalAssistant.WaitForSafeTP, + DollQuit = Config.BaalAssistant.DollQuit, + SoulQuit = Config.BaalAssistant.SoulQuit, + KillBaal = Config.BaalAssistant.KillBaal, + hotTPMessage = Config.BaalAssistant.HotTPMessage, // Not entriely needed in the configs. + safeTPMessage = Config.BaalAssistant.SafeTPMessage, // Not entriely needed in the configs. + baalMessage = Config.BaalAssistant.BaalMessage, // Doesn't need to be in configs. + nextGameMessage = Config.BaalAssistant.NextGameMessage, // Doesn't need to be in configs. + hotCheck = false, + safeCheck = false, + baalCheck = false, + ngCheck = false, + ShrineStatus = false, + secondAttempt = false, + throneStatus = false, + firstAttempt = true, + i, solofail, partymembers, baal, portal, tick, entrance; + + addEventListener('chatmsg', + + function (nick, msg) { + if (nick === Leader) { + for (i = 0; i < hotTPMessage.length; i += 1) { + if (msg.toLowerCase().indexOf(hotTPMessage[i].toLowerCase()) > -1) { + hotCheck = true; + break; + } + } + + for (i = 0; i < safeTPMessage.length; i += 1) { + if (msg.toLowerCase().indexOf(safeTPMessage[i].toLowerCase()) > -1) { + safeCheck = true; + break; + } + } + + for (i = 0; i < baalMessage.length; i += 1) { + if (msg.toLowerCase().indexOf(baalMessage[i].toLowerCase()) > -1) { + baalCheck = true; + break; + } + } + + for (i = 0; i < nextGameMessage.length; i += 1) { + if (msg.toLowerCase().indexOf(nextGameMessage[i].toLowerCase()) > -1) { + ngCheck = true; + break; + } + } + } + }); + + function autoLeaderDetect(destination) { + do { + solofail = 0; + partymembers = getParty(); + + do { + if (partymembers.name !== me.name) { + solofail += 1; + } + + if (partymembers.area === destination) { + Leader = partymembers.name; + return true; + } + } while (partymembers.getNext()); + + if (solofail === 0) { + throw new Error("BaalHelper: You were alone!"); + } + + delay(500); + + } while (!Leader); + + return false; + } + + this.preattack = function () { + var check; + switch (me.classid) { + case ClassID.Sorceress: + // Sorceress + if ([Skills.Sorceress.Lightning].indexOf(Config.AttackSkill[1]) > -1) { + if (me.getState(States.SKILLDELAY)) { + delay(500); + } else { + Skill.cast(Config.AttackSkill[1], 0, 15094, 5028); + } + } + if ([Skills.Sorceress.Chain_Lightning].indexOf(Config.AttackSkill[1]) > -1) { + if (me.getState(States.SKILLDELAY)) { + delay(500); + } else { + Skill.cast(Config.AttackSkill[1], 0, 15094, 5028); + } + } + if ([Skills.Sorceress.Meteor].indexOf(Config.AttackSkill[1]) > -1) { + if (me.getState(States.SKILLDELAY)) { + delay(500); + } else { + Skill.cast(Config.AttackSkill[1], 0, 15093, 5028); + } + } + if ([Skills.Sorceress.Blizzard].indexOf(Config.AttackSkill[1]) > -1) { + if (me.getState(States.SKILLDELAY)) { + delay(500); + } else { + Skill.cast(Config.AttackSkill[1], 0, 15095, 5028); + } + } + if ([Skills.Sorceress.Frozen_Orb].indexOf(Config.AttackSkill[1]) > -1) { + if (me.getState(States.SKILLDELAY)) { + delay(500); + } else { + Skill.cast(Config.AttackSkill[1], 0, 15094, 5028); + } + } + return true; + case ClassID.Paladin: + // Paladin + if (Config.AttackSkill[3] !== Skills.Paladin.Blessed_Hammer) { + return false; + } + if (getDistance(me, 15094, 5029) > 3) { + Pather.moveTo(15094, 5029); + } + if (Config.AttackSkill[4] > 0) { + Skill.setSkill(Config.AttackSkill[4], 0); + } + Skill.cast(Config.AttackSkill[3], 1); + return true; + case ClassID.Druid: + // Druid + if (Config.AttackSkill[3] === Skills.Druid.Tornado) { + Skill.cast(Config.AttackSkill[3], 0, 15094, 5028); + return true; + } + break; + case ClassID.Assassin: + // Assassin + if (Config.UseTraps) { + check = ClassAttack.checkTraps({ + x: 15094, + y: 5028 + }); + if (check) { + ClassAttack.placeTraps({ + x: 15094, + y: 5028 + }, 5); + return true; + } + } + break; + } + return false; + }; + + this.checkThrone = function () { + var monster = getUnit(UnitType.NPC); + if (monster) { + do { + if (Attack.checkMonster(monster) && monster.y < 5080) { + switch (monster.classid) { + case UnitClassID.fallen5: + case UnitClassID.fallenshaman5: + return 1; + case UnitClassID.unraveler5: + case UnitClassID.skmage_cold3: + return 2; + case UnitClassID.baalhighpriest: + return 3; + case UnitClassID.venomlord: + return 4; + case UnitClassID.baalminion1: + return 5; + default: + if (Helper) { + Attack.getIntoPosition(monster, 10, 0x4); + Attack.clear(15); + } + return false; + + } + } + } while (monster.getNext()); + } + return false; + }; + + this.clearThrone = function () { + var i, monster, + monList = [], + pos = [15094, 5022, 15094, 5041, 15094, 5060, 15094, 5041, 15094, 5022]; + if (Config.AvoidDolls) { + monster = getUnit(UnitType.NPC, UnitClassID.bonefetish7); + if (monster) { + do { + if (monster.x >= 15072 && monster.x <= 15118 && monster.y >= 5002 && monster.y <= 5079 && Attack.checkMonster(monster) && Attack.skipCheck(monster)) { + monList.push(copyUnit(monster)); + } + } while (monster.getNext()); + } + if (monList.length) { + Attack.clearList(monList); + } + } + for (i = 0; i < pos.length; i += 2) { + Pather.moveTo(pos[i], pos[i + 1]); + Attack.clear(25); + } + }; + + this.checkHydra = function () { + var monster = getUnit(UnitType.NPC, "hydra"); + if (monster) { + do { + if (monster.mode !== NPCModes.dead && monster.getStat(Stats.alignment) !== 2) { + Pather.moveTo(15072, 5002); + while (monster.mode !== NPCModes.dead) { + delay(500); + if (!copyUnit(monster).x) { + break; + } + } + break; + } + } while (monster.getNext()); + } + return true; + }; + + this.checkParty = function () { + var i, partycheck; + for (i = 0; i < Wait; i += 1) { + partycheck = getParty(); + if (partycheck) { + do { + if (partycheck.area === Areas.Act5.Throne_Of_Destruction) { + return false; + } + if (partycheck.area === Areas.Act4.River_Of_Flame || partycheck.area === Areas.Act4.Chaos_Sanctuary) { + return true; + } + } while (partycheck.getNext()); + } + delay(1000); + } + + if (i === Wait) { + throw new Error("No players in Throne of Destruction"); + } + + return false; + }; + + // Start + if (Leader) { + for (i = 0; i < 30; i += 1) { + if (Misc.inMyParty(Leader)) { + break; + } + delay(1000); + } + + if (i === 30) { + throw new Error("BaalHelper: Leader not partied"); + } + } + + if (KillNihlathak) { + include("bots/Nihlathak.js"); + + try { + Nihlathak(); + } catch (e) { + print(e); + } + } + + if (FastChaos) { + include("bots/FastDiablo.js"); + + try { + Town.goToTown(); + FastDiablo(); + } catch (e2) { + print(e2); + } + } + + Town.goToTown(5); + Town.doChores(); + + if (Leader || autoLeaderDetect(Areas.Act5.Harrogath) || autoLeaderDetect(Areas.Act5.The_Worldstone_Keep_Level_3) || autoLeaderDetect(Areas.Act5.Throne_Of_Destruction)) { + print("ÿc Areas.Act1.Rogue_Encampment; i -= 1) { + if (safeCheck) { + break; + } + if (Misc.getShrinesInArea(i, 15, true)) { + break; + } + } + + if (!safeCheck) { + if (i === 1) { + Town.goToTown(); + Pather.useWaypoint(Areas.Act1.Dark_Wood); + Precast.doPrecast(true); + + for (i = Areas.Act1.Dark_Wood; i < Areas.Act1.Den_Of_Evil; i += 1) { + if (safeCheck) { + break; + } + if (Misc.getShrinesInArea(i, 15, true)) { + break; + } + } + } + } + } + Town.goToTown(5); + ShrineStatus = true; + } + + if (firstAttempt && !secondAttempt && !safeCheck && !baalCheck && me.area !== Areas.Act5.Throne_Of_Destruction && me.area !== Areas.Act5.The_Worldstone_Chamber) { + if (RandomPrecast) { + Pather.useWaypoint("random"); + Precast.doPrecast(true); + } else { + Pather.useWaypoint(Areas.Act5.The_Worldstone_Keep_Level_2); + Precast.doPrecast(true); + } + } + + if (me.area !== Areas.Act5.Throne_Of_Destruction && me.area !== Areas.Act5.The_Worldstone_Chamber) { + if (SkipTP) { + if (firstAttempt && !secondAttempt) { + if (me.area !== Areas.Act5.The_Worldstone_Keep_Level_2) { + Pather.useWaypoint(Areas.Act5.The_Worldstone_Keep_Level_2); + } + if (!Pather.moveToExit([Areas.Act5.The_Worldstone_Keep_Level_3, Areas.Act5.Throne_Of_Destruction], false)) { + throw new Error("Failed to move to WSK3."); + } + + this.checkParty(); + + for (i = 0; i < 3; i += 1) { + entrance = getUnit(UnitType.Warp, 82); + + if (entrance) { + break; + } + + delay(200); + } + + if (entrance) { + Pather.moveTo(entrance.x > me.x ? entrance.x - 5 : entrance.x + 5, entrance.y > me.y ? entrance.y - 5 : entrance.y + 5); + } + + if (!Pather.moveToExit(Areas.Act5.Throne_Of_Destruction, true) || !Pather.moveTo(15118, 5002)) { + throw new Error("Failed to move to Throne of Destruction."); + } + + Pather.moveTo(15095, 5029); + + if ((SoulQuit && getUnit(UnitType.NPC, UnitClassID.willowisp7)) || (DollQuit && getUnit(UnitType.NPC, UnitClassID.bonefetish7))) { + print("Undead soul killers or Undead stygian dolls found, ending script."); + return true; + } + + Pather.moveTo(15118, 5002); + if (Helper) { + Attack.clear(15); + Pather.moveTo(15118, 5002); + } else { + Pather.moveTo(15117, 5045); + } + + secondAttempt = true; + safeCheck = true; + } else { + if (me.intown) { + Town.move("portalspot"); + Pather.usePortal(Areas.Act5.Throne_Of_Destruction, null); + if (me.mode === PlayerModes.Dead) { + me.revive(); + } + if (Helper) { + Attack.clear(15); + Pather.moveTo(15118, 5002); + } else { + Pather.moveTo(15117, 5045); + } + } + } + } else { + if (firstAttempt && !secondAttempt) { + if (me.area !== Areas.Act5.Harrogath) { + Pather.useWaypoint(Areas.Act5.Harrogath); + } + + Town.move("portalspot"); + + if (WaitForSafeTP) { + for (i = 0; i < Wait; i += 1) { + if (safeCheck) { + break; + } + delay(1000); + } + + if (i === Wait) { + throw new Error("No safe TP message."); + } + } + + for (i = 0; i < Wait; i += 1) { + if (Pather.usePortal(Areas.Act5.Throne_Of_Destruction, null)) { + break; + } + + delay(1000); + } + + if (i === Wait) { + throw new Error("No portals to Throne."); + } + + if ((SoulQuit && getUnit(UnitType.NPC, UnitClassID.bonefetish7)) || (DollQuit && getUnit(UnitType.NPC, UnitClassID.bonefetish6))) { + print("Undead soul killers or Undead stygian dolls found, ending script."); + return true; + } + + if (Helper) { + Attack.clear(15); + Pather.moveTo(15118, 5002); + } else { + Pather.moveTo(15117, 5045); + } + + secondAttempt = true; + safeCheck = true; + } else { + if (me.intown) { + Town.move("portalspot"); + Pather.usePortal(Areas.Act5.Throne_Of_Destruction, null); + if (me.mode === PlayerModes.Dead) { + me.revive(); + } + if (Helper) { + Attack.clear(15); + Pather.moveTo(15118, 5002); + } else { + Pather.moveTo(15117, 5045); + } + } + } + } + } + + for (i = 0; i < 5; i += 1) { + if (ngCheck) { + return true; + } + delay(100); + } + + if (safeCheck && !baalCheck && me.area === Areas.Act5.Throne_Of_Destruction && me.area !== Areas.Act5.The_Worldstone_Chamber) { + if (!baalCheck && !throneStatus) { + if (Helper) { + Attack.clear(15); + this.clearThrone(); + + Pather.moveTo(15094, me.classid === ClassID.Paladin ? 5029 : 5038); + Precast.doPrecast(true); + } + + tick = getTickCount(); + + MainLoop: while (true) { + if (Helper) { + if (getDistance(me, 15094, me.classid === ClassID.Paladin ? 5029 : 5038) > 3) { + Pather.moveTo(15094, me.classid === ClassID.Paladin ? 5029 : 5038); + } + } + + if (!getUnit(UnitType.NPC, UnitClassID.baalthrone)) { + break MainLoop; + } + + switch (this.checkThrone()) { + case 1: + if (Helper) { + Attack.clear(40); + } + tick = getTickCount(); + + break; + case 2: + if (Helper) { + Attack.clear(40); + } + tick = getTickCount(); + + break; + case 4: + if (Helper) { + Attack.clear(40); + } + tick = getTickCount(); + + break; + case 3: + if (Helper) { + Attack.clear(40); + this.checkHydra(); + } + + tick = getTickCount(); + + break; + case 5: + if (Helper) { + Attack.clear(40); + } else { + while (Attack.checkMonster(getUnit(UnitType.NPC, UnitClassID.baalminion1)) || Attack.checkMonster(getUnit(UnitType.NPC, UnitClassID.baalminion2)) || Attack.checkMonster(getUnit(UnitType.NPC, UnitClassID.baalminion3))) { + delay(1000); + } + delay(1000); + } + + break MainLoop; + default: + if (getTickCount() - tick < 7e3) { + if (me.getState(States.POISON)) { + Skill.setSkill(Skills.Paladin.Cleansing, 0); + } + + break; + } + + if (Helper) { + if (!this.preattack()) { + delay(100); + } + } + + break; + } + delay(10); + } + throneStatus = true; + baalCheck = true; + } + } + + for (i = 0; i < 5; i += 1) { + if (ngCheck) { + return true; + } + delay(100); + } + + if ((throneStatus || baalCheck) && KillBaal && me.area === Areas.Act5.Throne_Of_Destruction) { + if (Helper) { + Pather.moveTo(15090, 5008); + delay(2000); + Precast.doPrecast(true); + } else { + Pather.moveTo(15090, 5010); + Precast.doPrecast(true); + } + + while (getUnit(UnitType.NPC, UnitClassID.baalthrone)) { + delay(500); + } + + portal = getUnit(UnitType.Object, UniqueObjectIds.Worldstone_Chamber); + + if (portal) { + if (Helper) { + delay(1000); + } else { + delay(4000); + } + Pather.usePortal(null, null, portal); + } else { + throw new Error("Couldn't find portal."); + } + + if (me.mode === PlayerModes.Dead) { + me.revive(); + } + + if (Helper) { + delay(1000); + Pather.moveTo(15134, 5923); + baal = getUnit(UnitType.NPC, UnitClassID.baalcrab); + Attack.kill(UnitClassID.baalcrab); + Pickit.pickItems(); + if (ngCheck) { + return true; + } + if (baal && (baal.mode === NPCModes.death || baal.mode === NPCModes.dead)) { + return true; + } + } else { + Pather.moveTo(15177, 5952); + baal = getUnit(UnitType.NPC, UnitClassID.baalcrab); + while (baal) { + delay(1000); + if (ngCheck) { + return true; + } + if (baal && (baal.mode === NPCModes.death || baal.mode === NPCModes.dead)) { + return true; + } + } + return true; + } + + } else { + while (true) { + if (ngCheck) { + return true; + } + delay(500); + } + } + + delay(500); + } + } else { + throw new Error("Empty game."); + } + + return true; +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/BaalHelper.js b/d2bs/kolbot/libs/bots/BaalHelper.js index e1ee4a4ae..a744e45a2 100644 --- a/d2bs/kolbot/libs/bots/BaalHelper.js +++ b/d2bs/kolbot/libs/bots/BaalHelper.js @@ -1,290 +1,100 @@ /** -* @filename BaalHelper.js +* @filename BattleOrders.js * @author kolton -* @desc help the leading player in clearing Throne of Destruction and killing Baal +* @desc give or receive Battle Orders buff */ -function BaalHelper() { // experi-mental - this.preattack = function () { - var check; - - switch (me.classid) { - case 1: - if ([56, 59, 64].indexOf(Config.AttackSkill[1]) > -1) { - if (me.getState(121)) { - delay(500); - } else { - Skill.cast(Config.AttackSkill[1], 0, 15093, 5024); - } - } - - return true; - case 3: // Paladin - if (Config.AttackSkill[3] !== 112) { - return false; - } - - if (getDistance(me, 15093, 5029) > 3) { - Pather.moveTo(15093, 5029); - } - - if (Config.AttackSkill[4] > 0) { - Skill.setSkill(Config.AttackSkill[4], 0); - } - - Skill.cast(Config.AttackSkill[3], 1); - - return true; - case 5: // Druid - if (Config.AttackSkill[3] === 245) { - Skill.cast(Config.AttackSkill[3], 0, 15093, 5029); - - return true; - } - - break; - case 6: // Assassin - if (Config.UseTraps) { - check = ClassAttack.checkTraps({x: 15093, y: 5029}); - - if (check) { - ClassAttack.placeTraps({x: 15093, y: 5029}, 5); - - return true; - } - } - - break; - } - - return false; - }; - - this.checkThrone = function () { - var monster = getUnit(1); - - if (monster) { - do { - if (Attack.checkMonster(monster) && monster.y < 5080) { - switch (monster.classid) { - case 23: - case 62: - return 1; - case 105: - case 381: - return 2; - case 557: - return 3; - case 558: - return 4; - case 571: - return 5; - default: - Attack.getIntoPosition(monster, 10, 0x4); - Attack.clear(15); - - return false; - } - } - } while (monster.getNext()); - } - - return false; - }; - - this.clearThrone = function () { - var i, monster, - monList = [], - pos = [15097, 5054, 15085, 5053, 15085, 5040, 15098, 5040, 15099, 5022, 15086, 5024]; - - if (Config.AvoidDolls) { - monster = getUnit(1, 691); - - if (monster) { - do { - if (monster.x >= 15072 && monster.x <= 15118 && monster.y >= 5002 && monster.y <= 5079 && Attack.checkMonster(monster) && Attack.skipCheck(monster)) { - monList.push(copyUnit(monster)); - } - } while (monster.getNext()); - } - - if (monList.length) { - Attack.clearList(monList); - } - } - - for (i = 0; i < pos.length; i += 2) { - Pather.moveTo(pos[i], pos[i + 1]); - Attack.clear(30); - } - }; - - this.checkHydra = function () { - var monster = getUnit(1, "hydra"); - - if (monster) { - do { - if (monster.mode !== 12 && monster.getStat(172) !== 2) { - Pather.moveTo(15118, 5002); +function BattleOrders() { + this.giveBO = function (list) { + var i, unit, + failTimer = 60, + tick = getTickCount(); - while (monster.mode !== 12) { - delay(500); + for (i = 0; i < list.length; i += 1) { + unit = getUnit(0, list[i]); - if (!copyUnit(monster).x) { - break; - } + if (unit) { + while (!unit.getState(States.BATTLEORDERS) && copyUnit(unit).x) { + if (getTickCount() - tick >= failTimer * 1000) { + showConsole(); + print("ÿc1BO timeout fail."); + quit(); } - break; + Precast.doPrecast(true); + delay(1000); } - } while (monster.getNext()); + } } return true; }; - if (Config.BaalHelper.KillNihlathak) { - include("bots/Nihlathak.js"); - - try { - Nihlathak(); - } catch (e) { - print(e); - } - } - - if (Config.BaalHelper.FastChaos) { - include("bots/FastDiablo.js"); - - try { - Town.goToTown(); - FastDiablo(); - } catch (e2) { - print(e2); - } - } - - var i, tick, portal; - - Town.goToTown(5); Town.doChores(); - if (!me.getState(32)) { - Pather.useWaypoint(129); - Precast.doPrecast(true); - Pather.useWaypoint(109); + try { + Pather.useWaypoint(Areas.Act1.Catacombs_Level_2, true); // catacombs + } catch (wperror) { + showConsole(); + print("ÿc1Failed to take waypoint."); + quit(); } - Town.move("portalspot"); - - for (i = 0; i < 180; i += 1) { - if (Pather.usePortal(131, null)) { - break; - } - - delay(1000); - } - - if (i === 180) { - throw new Error("No portals to Throne"); - } + Pather.moveTo(me.x + 6, me.y + 6); - if (Config.BaalHelper.DollQuit && getUnit(1, 691)) { - print("Soul Killers found."); - - return true; - } - - Precast.doPrecast(false); - Attack.clear(15); - this.clearThrone(); - - tick = getTickCount(); - - Pather.moveTo(15093, me.classid === 3 ? 5029 : 5039); + var i, + tick = getTickCount(), + failTimer = 60; MainLoop: while (true) { - if (getDistance(me, 15093, me.classid === 3 ? 5029 : 5039) > 3) { - Pather.moveTo(15093, me.classid === 3 ? 5029 : 5039); - } - - if (!getUnit(1, 543)) { - break MainLoop; - } - - switch (this.checkThrone()) { - case 1: - Attack.clear(40); - - tick = getTickCount(); - - Precast.doPrecast(true); - - break; - case 2: - Attack.clear(40); - - tick = getTickCount(); - - break; - case 4: - Attack.clear(40); - - tick = getTickCount(); + switch (Config.BattleOrders.Mode) { + case 0: // Give BO + for (i = 0; i < Config.BattleOrders.Getters.length; i += 1) { + while (!Misc.inMyParty(Config.BattleOrders.Getters[i]) || !getUnit(0, Config.BattleOrders.Getters[i])) { + if (getTickCount() - tick >= failTimer * 1000) { + showConsole(); + print("ÿc1BO timeout fail."); + quit(); + } - break; - case 3: - Attack.clear(40); - this.checkHydra(); + delay(500); + } + } - tick = getTickCount(); + if (this.giveBO(Config.BattleOrders.Getters)) { + break MainLoop; + } break; - case 5: - Attack.clear(40); + case 1: // Get BO + if (me.getState(States.BATTLEORDERS)) { + delay(1000); - break MainLoop; - default: - if (getTickCount() - tick < 7e3) { - if (me.getState(2)) { - Skill.setSkill(109, 0); - } - - break; + break MainLoop; } - if (!this.preattack()) { - delay(100); + if (getTickCount() - tick >= failTimer * 1000) { + showConsole(); + print("ÿc1BO timeout fail."); + quit(); } break; } - Precast.doPrecast(false); - delay(10); - } - - Pather.moveTo(15092, 5011); - Precast.doPrecast(false); - - while (getUnit(1, 543)) { delay(500); } - delay(1000); - - portal = getUnit(2, 563); + Pather.useWaypoint(Areas.Act1.Rogue_Encampment); - if (portal) { - Pather.usePortal(null, null, portal); - } else { - throw new Error("Couldn't find portal."); + if (Config.BattleOrders.Mode === 0 && Config.BattleOrders.Wait) { + for (i = 0; i < Config.BattleOrders.Getters.length; i += 1) { + while (Misc.inMyParty(Config.BattleOrders.Getters[i])) { + delay(500); + } + } } - Pather.moveTo(15134, 5923); - Attack.kill(544); // Baal - Pickit.pickItems(); - return true; } \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/BattleOrders.js b/d2bs/kolbot/libs/bots/BattleOrders.js index e11fdb55d..5c1fc6fc5 100644 --- a/d2bs/kolbot/libs/bots/BattleOrders.js +++ b/d2bs/kolbot/libs/bots/BattleOrders.js @@ -5,64 +5,102 @@ */ function BattleOrders() { - Pather.useWaypoint(35); // catacombs - Pather.moveTo(me.x + 5, me.y); - - var bo, leader, - count = 0; + this.giveBO = function (list) { + var i, unit, + failTimer = 20, + tick = getTickCount(); + + for (i = 0; i < list.length; i += 1) { + unit = getUnit(0, list[i]); + + if (unit) { + while (!unit.getState(States.BATTLEORDERS) && copyUnit(unit).x) { + if (getTickCount() - tick >= failTimer * 1000) { + showConsole(); + print("ÿc1BO timeout fail."); + //quit(); + Precast.doPrecast(true); + delay(1000); + return false; + } + + Precast.doPrecast(true); + delay(1000); + } + } + } - function ChatEvent(nick, msg) { - var playerPartyid = getParty(nick).partyid; + return true; + }; - if (msg === "BO" && playerPartyid !== 65535 && playerPartyid === getParty().partyid) { - removeEventListener("chatmsg", ChatEvent); + Town.doChores(); - bo = true; - leader = nick; - } + try { + Pather.useWaypoint(Areas.Act1.Catacombs_Level_2, true); // catacombs + } catch (wperror) { + showConsole(); + print("ÿc1Failed to take waypoint."); + //quit(); + return false; } - if (Config.BattleOrders.Mode === 0) { - addEventListener("chatmsg", ChatEvent); - } + Pather.moveTo(me.x + 6, me.y + 6); + + var i, + tick = getTickCount(), + failTimer = 20; MainLoop: while (true) { switch (Config.BattleOrders.Mode) { - case 0: - if (bo) { - Precast.doPrecast(true); + case 0: // Give BO + for (i = 0; i < Config.BattleOrders.Getters.length; i += 1) { + while (!Misc.inMyParty(Config.BattleOrders.Getters[i]) || !getUnit(UnitType.Player, Config.BattleOrders.Getters[i])) { + if (getTickCount() - tick >= failTimer * 1000) { + Precast.doPrecast(true); + delay(1000); + showConsole(); + print("ÿc1BO timeout fail."); + //quit(); + return false; + } + + delay(500); + } + } + if (this.giveBO(Config.BattleOrders.Getters)) { break MainLoop; } break; - case 1: - if (me.getState(32)) { - break MainLoop; - } + case 1: // Get BO + if (me.getState(Areas.Act1.Inner_Cloister)) { + delay(1000); - if (count % 10 === 0) { // say "BO" every 5 seconds - say("BO"); + break MainLoop; } - if (count > 60) { // 30 seconds with no bo - throw new Error("Failed to get BO"); + if (getTickCount() - tick >= (failTimer + 5) * 1000) { + showConsole(); + print("ÿc1BO timeout fail."); + //quit(); + return false; } break; } delay(500); - - count += 1; } - Pather.useWaypoint(1); + Pather.useWaypoint(Areas.Act1.Rogue_Encampment); if (Config.BattleOrders.Mode === 0 && Config.BattleOrders.Wait) { - while (Misc.inMyParty(leader)) { - delay(1000); + for (i = 0; i < Config.BattleOrders.Getters.length; i += 1) { + while (Misc.inMyParty(Config.BattleOrders.Getters[i])) { + delay(500); + } } } diff --git a/d2bs/kolbot/libs/bots/BoneAsh.js b/d2bs/kolbot/libs/bots/BoneAsh.js index 8f478c61c..7d62599c4 100644 --- a/d2bs/kolbot/libs/bots/BoneAsh.js +++ b/d2bs/kolbot/libs/bots/BoneAsh.js @@ -6,7 +6,7 @@ function BoneAsh() { Town.doChores(); - Pather.useWaypoint(32); + Pather.useWaypoint(Areas.Act1.Inner_Cloister); Precast.doPrecast(true); if (!Pather.moveTo(20047, 4898)) { diff --git a/d2bs/kolbot/libs/bots/Bonesaw.js b/d2bs/kolbot/libs/bots/Bonesaw.js index 2777503ed..7b8c2019d 100644 --- a/d2bs/kolbot/libs/bots/Bonesaw.js +++ b/d2bs/kolbot/libs/bots/Bonesaw.js @@ -6,14 +6,18 @@ function Bonesaw() { Town.doChores(); - Pather.useWaypoint(115); + Pather.useWaypoint(Areas.Act5.Glacial_Trail); Precast.doPrecast(true); - if (!Pather.moveToPreset(115, 2, 455, 15, 15)) { + if (!Pather.moveToPreset(Areas.Act5.Glacial_Trail, UnitType.Object, UniqueObjectIds.Special_Chest, 15, 15)) { throw new Error("Failed to move to Bonesaw"); } Attack.clear(15, 0, getLocaleString(22502)); // Bonesaw Breaker + if (Config.Bonesaw.ClearDrifterCavern && Pather.moveToExit(Areas.Act5.Drifter_Cavern, true)) { + Attack.clearLevel(Config.ClearType); + } + return true; } \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/ChestMania.js b/d2bs/kolbot/libs/bots/ChestMania.js new file mode 100644 index 000000000..df54d105d --- /dev/null +++ b/d2bs/kolbot/libs/bots/ChestMania.js @@ -0,0 +1,24 @@ +/** +* @filename ChestMania.js +* @author kolton +* @desc Open chests in configured areas +*/ + +function ChestMania() { + var prop, i; + + Town.doChores(); + + for (prop in Config.ChestMania) { + if (Config.ChestMania.hasOwnProperty(prop)) { + for (i = 0; i < Config.ChestMania[prop].length; i += 1) { + Pather.journeyTo(Config.ChestMania[prop][i]); + Misc.openChestsInArea(Config.ChestMania[prop][i]); + } + + Town.doChores(); + } + } + + return true; +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/ClassicChaosAssistant.js b/d2bs/kolbot/libs/bots/ClassicChaosAssistant.js new file mode 100644 index 000000000..3c06275ee --- /dev/null +++ b/d2bs/kolbot/libs/bots/ClassicChaosAssistant.js @@ -0,0 +1,216 @@ +/** + * @filename ClassicChaosAssistant.js + * @author YGM + * @desc Assistant to help sorcs in public chaos runs games on classic. + */ + +function Idle() { + + var stargo, infgo, seisgo, vizgo, infseal, seisseal, vizseal, diablopickup, normalpickup = false, i, tick, seal, boss, n, target, positions, trapCheck; + + this.getLayout = function (seal, value) { + var sealPreset = getPresetUnit(Areas.Act4.Chaos_Sanctuary, UnitType.Object, seal); + + if (!seal) { + throw new Error("Seal preset not found. Can't continue."); + } + + if (sealPreset.roomy * 5 + sealPreset.y === value || sealPreset.roomx * 5 + sealPreset.x === value) { + return 1; + } + + return 2; + }; + + this.initLayout = function () { + this.vizLayout = this.getLayout(UniqueObjectIds.Diablo_Seal5, 5275); + this.seisLayout = this.getLayout(UniqueObjectIds.Diablo_Seal3, 7773); + this.infLayout = this.getLayout(UniqueObjectIds.Diablo_Seal1, 7893); + }; + + this.openSeal = function (id) { + Pather.moveToPreset(Areas.Act4.Chaos_Sanctuary, UnitType.Object, id, 4); + + seal = getUnit(2, id); + + if (seal) { + for (i = 0; i < 3; i += 1) { + seal.interact(); + + tick = getTickCount(); + + while (getTickCount() - tick < 500) { + if (seal.mode) { + return true; + } + + delay(10); + } + } + } + + return false; + }; + + addEventListener("keyup", + + function (key) { + if (key === 97) { // Numpad 1 + stargo = true; + } + if (key === 98) { // Numpad 2 + infgo = true; + } + if (key === 99) { // Numpad 3 + infseal = true; + } + if (key === 100) { // Numpad 4 + seisgo = true; + } + if (key === 101) { // Numpad 5 (YOU MUST DISABLE KOLTONS MULETRIGGER!) + seisseal = true; + } + if (key === 102) { // Numpad 6 + vizgo = true; + } + if (key === 103) { // Numpad 7 + vizseal = true; + } + if (key === 104) { // Numpad 8 (Open last seal, teleport to star and pickup for 30 seconds) + diablopickup = true; + } + if (key === 105) { // Numpad 9 (Pickup at current location) + normalpickup = true; + } + }); + + while (true) { + if (stargo) { + switch (me.area) { + case Areas.Act4.River_Of_Flame: + Precast.doPrecast(true); + Pather.moveToPreset(Areas.Act4.Chaos_Sanctuary, UnitType.Object, UniqueObjectIds.Diablo_Start_Point); + this.initLayout(); + break; + } + stargo = false; + } + + if (infgo) { + switch (me.area) { + case Areas.Act4.Chaos_Sanctuary: + if (this.infLayout === 1) { + Pather.moveTo(7893, 5306); + } else { + Pather.moveTo(7929, 5294); + } + Pather.makePortal(); + say("Infector of Souls TP Up!"); + break; + } + infgo = false; + } + + if (seisgo) { + switch (me.area) { + case Areas.Act4.Chaos_Sanctuary: + if (this.seisLayout === 1) { + Pather.moveTo(7773, 5191); + } else { + Pather.moveTo(7794, 5189); + } + Pather.makePortal(); + say("Lord De Seis TP Up!"); + break; + } + seisgo = false; + } + + if (vizgo) { + switch (me.area) { + case Areas.Act4.Chaos_Sanctuary: + if (this.vizLayout === 1) { + Pather.moveTo(7681, 5302); + } else { + Pather.moveTo(7675, 5305); + } + Pather.makePortal(); + say("Grand Vizier of Chaos TP Up!"); + break; + } + vizgo = false; + } + + if (infseal) { + switch (me.area) { + case Areas.Act4.Chaos_Sanctuary: + this.openSeal(UniqueObjectIds.Diablo_Seal2) + this.openSeal(UniqueObjectIds.Diablo_Seal1) + say("Infector of Souls spawned!"); + if (this.infLayout === 1) { + Pather.moveTo(7893, 5306); + } else { + Pather.moveTo(7929, 5294); + } + break; + } + infseal = false; + } + + if (seisseal) { + switch (me.area) { + case Areas.Act4.Chaos_Sanctuary: + this.openSeal(UniqueObjectIds.Diablo_Seal3) + say("Lord De Seis spawned!"); + if (this.seisLayout === 1) { + Pather.moveTo(7773, 5191); + } else { + Pather.moveTo(7794, 5189); + } + break; + } + seisseal = false; + } + + if (vizseal) { + switch (me.area) { + case Areas.Act4.Chaos_Sanctuary: + this.openSeal(UniqueObjectIds.Diablo_Seal5) + say("Grand Vizier of Chaos spawned!"); + if (this.vizLayout === 1) { + Pather.moveTo(7681, 5302); + } else { + Pather.moveTo(7675, 5305); + } + break; + } + vizseal = false; + } + + if (diablopickup) { + switch (me.area) { + case Areas.Act4.Chaos_Sanctuary: + this.openSeal(UniqueObjectIds.Diablo_Seal4) + Pather.moveToPreset(108, 2, 255); + for (i = 0; i < 300; i += 1) { + Pickit.pickItems(); + delay(100); + } + break; + } + diablopickup = false; + } + + if (normalpickup) { + switch (me.area) { + case Areas.Act4.Chaos_Sanctuary: + Pickit.pickItems(); + break; + } + normalpickup = false; + } + + delay(10); + } + +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/ClearAnyArea.js b/d2bs/kolbot/libs/bots/ClearAnyArea.js new file mode 100644 index 000000000..d3eec098e --- /dev/null +++ b/d2bs/kolbot/libs/bots/ClearAnyArea.js @@ -0,0 +1,19 @@ +/** +* @filename ClearAnyArea.js +* @author kolton +* @desc Clears any area +*/ + +function ClearAnyArea() { + var i; + + Town.doChores(); + + for (i = 0; i < Config.ClearAnyArea.AreaList.length; i += 1) { + if (Pather.journeyTo(Config.ClearAnyArea.AreaList[i])) { + Attack.clearLevel(Config.ClearType); + } + } + + return true; +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/Coldcrow.js b/d2bs/kolbot/libs/bots/Coldcrow.js index 5a21bd7e2..c56c00f11 100644 --- a/d2bs/kolbot/libs/bots/Coldcrow.js +++ b/d2bs/kolbot/libs/bots/Coldcrow.js @@ -6,14 +6,14 @@ function Coldcrow() { Town.doChores(); - Pather.useWaypoint(3); + Pather.useWaypoint(Areas.Act1.Cold_Plains); Precast.doPrecast(true); - if (!Pather.moveToExit(9, true, false)) { + if (!Pather.moveToExit(Areas.Act1.Cave_Level_1, true, false)) { throw new Error("Failed to move to Cave"); } - if (!Pather.moveToPreset(me.area, 1, 736, 5, 5, false)) { + if (!Pather.moveToPreset(me.area, UnitType.NPC, SuperUniques.Coldcrow, 0, 0, false)) { throw new Error("Failed to move to Coldcrow"); } diff --git a/d2bs/kolbot/libs/bots/Coldworm.js b/d2bs/kolbot/libs/bots/Coldworm.js new file mode 100644 index 000000000..d07cf584b --- /dev/null +++ b/d2bs/kolbot/libs/bots/Coldworm.js @@ -0,0 +1,42 @@ +/** +* @filename Coldworm.js +* @author kolton, edited by 13ack.Stab +* @desc kill Coldworm; optionally kill Beetleburst and clear Maggot Lair +*/ + +function Coldworm() { + var i; + + Town.doChores(); + Pather.useWaypoint(Areas.Act2.Far_Oasis); + Precast.doPrecast(true); + + // Beetleburst, added by 13ack.Stab + if (Config.Coldworm.KillBeetleburst) { + if (!Pather.moveToPreset(me.area, UnitType.NPC, SuperUniques.Beetleburst)) { + throw new Error("Failed to move to Beetleburst"); + } + + Attack.clear(15, 0, getLocaleString(2882)); + } + + for (i = 62; i <= 64; i += 1) { + if (!Pather.moveToExit(i, true)) { + throw new Error("Failed to move to Coldworm"); + } + + if (Config.Coldworm.ClearMaggotLair) { + Attack.clearLevel(Config.ClearType); + } + } + + if (!Config.Coldworm.ClearMaggotLair) { + if (!Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Staff_Of_Kings_Chest)) { + throw new Error("Failed to move to Coldworm"); + } + + Attack.clear(15, 0, UnitClassID.maggotqueen1); + } + + return true; +} diff --git a/d2bs/kolbot/libs/bots/Corpsefire.js b/d2bs/kolbot/libs/bots/Corpsefire.js index fb2ef6b9e..f5408504f 100644 --- a/d2bs/kolbot/libs/bots/Corpsefire.js +++ b/d2bs/kolbot/libs/bots/Corpsefire.js @@ -6,10 +6,10 @@ function Corpsefire() { Town.doChores(); - Pather.useWaypoint(3); + Pather.useWaypoint(Areas.Act1.Cold_Plains); Precast.doPrecast(true); - if (!Pather.moveToExit([2, 8], true) || !Pather.moveToPreset(me.area, 1, 774, 0, 0, false, true)) { + if (!Pather.moveToExit([Areas.Act1.Blood_Moor, Areas.Act1.Den_Of_Evil], true) || !Pather.moveToPreset(me.area, UnitType.NPC, SuperUniques.Corpsefire, 0, 0, false, true)) { throw new Error("Failed to move to Corpsefire"); } diff --git a/d2bs/kolbot/libs/bots/Countess.js b/d2bs/kolbot/libs/bots/Countess.js index ac5be6a06..41218f70c 100644 --- a/d2bs/kolbot/libs/bots/Countess.js +++ b/d2bs/kolbot/libs/bots/Countess.js @@ -5,17 +5,17 @@ */ function Countess() { - var poi; + var i, poi; Town.doChores(); - Pather.useWaypoint(6); + Pather.useWaypoint(Areas.Act1.Black_Marsh); Precast.doPrecast(true); - if (!Pather.moveToExit([20, 21, 22, 23, 24, 25], true)) { - throw new Error("Failed to move to Tower Cellar level 5"); + if (!Pather.moveToExit([Areas.Act1.Forgotten_Tower, Areas.Act1.Tower_Cellar_Level_1, Areas.Act1.Tower_Cellar_Level_2, Areas.Act1.Tower_Cellar_Level_3, Areas.Act1.Tower_Cellar_Level_4, Areas.Act1.Tower_Cellar_Level_5], true)) { + throw new Error("Failed to move to Countess"); } - poi = getPresetUnit(me.area, 2, 580); + poi = getPresetUnit(me.area, UnitType.Object, 580); if (!poi) { throw new Error("Failed to move to Countess (preset not found)"); @@ -32,5 +32,9 @@ function Countess() { Attack.clear(20, 0, getLocaleString(2875)); // The Countess + if (Config.OpenChests) { + Misc.openChestsInArea(); + } + return true; } \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/Cows.js b/d2bs/kolbot/libs/bots/Cows.js index 9ccb9ae09..e3588d76f 100644 --- a/d2bs/kolbot/libs/bots/Cows.js +++ b/d2bs/kolbot/libs/bots/Cows.js @@ -10,7 +10,7 @@ function Cows() { finalRooms = [], indexes = []; - kingPreset = getPresetUnit(me.area, 1, 773); + kingPreset = getPresetUnit(me.area, UnitType.NPC, SuperUniques.The_Cow_King); badRooms = getRoom(kingPreset.roomx * 5 + kingPreset.x, kingPreset.roomy * 5 + kingPreset.y).getNearby(); for (i = 0; i < badRooms.length; i += 1) { @@ -33,13 +33,35 @@ function Cows() { return finalRooms; }; - + this.clearCowLevel = function () { - var room, result, + if (Config.MFLeader) { + Pather.makePortal(); + say("cows"); + } + + var room, result, myRoom, rooms = this.buildCowRooms(); - while (rooms.length) { - rooms.sort(Sort.points); + function RoomSort(a, b) { + return getDistance(myRoom[0], myRoom[1], a[0], a[1]) - getDistance(myRoom[0], myRoom[1], b[0], b[1]); + } + + while (rooms.length > 0) { + // get the first room + initialize myRoom var + if (!myRoom) { + room = getRoom(me.x, me.y); + } + + if (room) { + if (room instanceof Array) { // use previous room to calculate distance + myRoom = [room[0], room[1]]; + } else { // create a new room to calculate distance (first room, done only once) + myRoom = [room.x * 5 + room.xsize / 2, room.y * 5 + room.ysize / 2]; + } + } + + rooms.sort(RoomSort); room = rooms.shift(); result = Pather.getNearestWalkable(room[0], room[1], 10, 2); @@ -47,30 +69,28 @@ function Cows() { if (result) { Pather.moveTo(result[0], result[1], 3); - if (!Attack.clear(25)) { + if (!Attack.clear(30)) { return false; } } } - CollMap.reset(); - return true; }; this.getLeg = function () { var i, portal, wirt, leg, gid; - if (me.getItem(88)) { - return me.getItem(88); + if (me.getItem(ItemClassIds.Wirts_Leg)) { + return me.getItem(ItemClassIds.Wirts_Leg); } - Pather.useWaypoint(4); + Pather.useWaypoint(Areas.Act1.Stony_Field); Precast.doPrecast(true); - Pather.moveToPreset(me.area, 1, 737, 8, 8); + Pather.moveToPreset(me.area, UnitType.NPC, SuperUniques.Rakanishu, 8, 8); for (i = 0; i < 6; i += 1) { - portal = Pather.getPortal(38); + portal = Pather.getPortal(Areas.Act1.Tristram); if (portal) { Pather.usePortal(null, null, portal); @@ -87,13 +107,13 @@ function Cows() { Pather.moveTo(25048, 5177); - wirt = getUnit(2, 268); + wirt = getUnit(UnitType.Object, UniqueObjectIds.Wirts_Body); for (i = 0; i < 8; i += 1) { wirt.interact(); delay(500); - leg = getUnit(4, 88); + leg = getUnit(UnitType.Item, ItemClassIds.Wirts_Leg); if (leg) { gid = leg.gid; @@ -110,7 +130,7 @@ function Cows() { this.getTome = function () { var tome, - myTome = me.findItem("tbk", 0, 3), + myTome = me.findItem("tbk", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory), akara = Town.initNPC("Shop"); tome = me.getItem("tbk"); @@ -163,7 +183,7 @@ function Cows() { delay(500); for (i = 0; i < 10; i += 1) { - if (Pather.getPortal(39)) { + if (Pather.getPortal(Areas.Act1.Moo_Moo_Farm)) { return true; } @@ -176,13 +196,37 @@ function Cows() { var leg, tome; // we can begin now + if (me.getQuest(Quests.Act1.The_Search_for_Cain, 10)) { // king dead or cain not saved + throw new Error("Already killed the Cow King."); + } + + if (!me.getQuest(Quests.Act1.The_Search_for_Cain, 0)) { + throw new Error("Cain quest incomplete"); + } + + switch (me.gametype) { + case GameType.Classic: // classic + if (!me.getQuest(Quests.Act4.Terrors_End, 0)) { // diablo not completed + throw new Error("Diablo quest incomplete."); + } + + break; + case GameType.Expansion: // expansion + if (!me.getQuest(Quests.Act5.Eve_of_Destruction, 0)) { // baal not completed + throw new Error("Baal quest incomplete."); + } + + break; + } + + Town.goToTown(1); Town.doChores(); leg = this.getLeg(); tome = this.getTome(); this.openPortal(leg, tome); - Pather.usePortal(39); + Pather.usePortal(Areas.Act1.Moo_Moo_Farm); Precast.doPrecast(false); this.clearCowLevel(); diff --git a/d2bs/kolbot/libs/bots/Crafting.js b/d2bs/kolbot/libs/bots/Crafting.js new file mode 100644 index 000000000..4bbbe539b --- /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 ItemClassIds.Light_Belt: // Light Belt + case ItemClassIds.Sharkskin_Belt: // Sharkskin Belt + return "elzix"; + case ItemClassIds.Belt: // Belt + case ItemClassIds.Mesh_Belt: // Mesh Belt + case ItemClassIds.Light_Plated_Boots: // Light Plated Boots + case ItemClassIds.Battle_Boots: // 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, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); + + 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, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); + + 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(UnitType.Item, -1, ItemLocation.Inventory); + + if (item) { + updateInfo(); + + do { + if (checkItem(item) || item.classid === ItemClassIds.Gold || 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 === NPCModes.walk) { + 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(Stats.gold) + me.getStat(Stats.goldbank) >= 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 = Areas.Act2.Lut_Gholein; + 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(UnitType.NPC, NPC.Fara); + + break; + case "elzix": + wpArea = 48; + town = Areas.Act2.Lut_Gholein; + path = [5038, 5099, 5059, 5102, 5068, 5090, 5067, 5086]; + menuId = "Shop"; + + Town.goToTown(2); + + if (!getUnit(UnitType.NPC, NPC.Elzix)) { + Town.move(NPC.Elzix); + } + + npc = getUnit(1, NPC.Elzix); + + break; + case "drognan": + wpArea = 48; + town = Areas.Act2.Lut_Gholein; + 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(UnitType.NPC, NPC.Drognan); + + break; + case "ormus": + wpArea = 101; + town = Areas.Act3.Kurast_Docktown; + 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(UnitType.NPC, NPC.Ormus); + + break; + case "anya": + wpArea = 129; + town = Areas.Act5.Harrogath; + 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(UnitType.NPC, NPC.Anya); + + break; + case "malah": + wpArea = 113; + town = Areas.Act5.Harrogath; + 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(UnitType.NPC, 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 d5958ea53..af46cb1e7 100644 --- a/d2bs/kolbot/libs/bots/Diablo.js +++ b/d2bs/kolbot/libs/bots/Diablo.js @@ -5,18 +5,55 @@ */ function Diablo() { - // sort functions - this.entranceSort = function (a, b) { - return getDistance(a.x, a.y, 7790, 5544) - getDistance(b.x, b.y, 7790, 5544); - }; + // 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; + } + } - this.starSort = function (a, b) { - return getDistance(a.x, a.y, 7774, 5305) - getDistance(b.x, b.y, 7774, 5305); + // Entrance to Star / De Seis + if (me.y > 5325 || me.y < 5260) { + if (a.y > b.y) { + return -1; + } + + return 1; + } + + // Vizier + if (me.x < 7765) { + if (a.x > b.x) { + return -1; + } + + return 1; + } + + // Infector + if (me.x > 7825) { + if (!checkCollision(me, a, 0x1) && a.x < b.x) { + return -1; + } + + return 1; + } + + return getDistance(me, a) - getDistance(me, b); }; // general functions this.getLayout = function (seal, value) { - var sealPreset = getPresetUnit(108, 2, seal); + var sealPreset = getPresetUnit(Areas.Act4.Chaos_Sanctuary, UnitType.Object, seal); if (!seal) { throw new Error("Seal preset not found. Can't continue."); @@ -30,29 +67,31 @@ function Diablo() { }; this.initLayout = function () { - this.vizLayout = this.getLayout(396, 5275); - this.seisLayout = this.getLayout(394, 7773); - this.infLayout = this.getLayout(392, 7893); + this.vizLayout = this.getLayout(UniqueObjectIds.Diablo_Seal5, 5275); + this.seisLayout = this.getLayout(UniqueObjectIds.Diablo_Seal3, 7773); + this.infLayout = this.getLayout(UniqueObjectIds.Diablo_Seal1, 7893); }; this.openSeal = function (classid) { var i, seal, warn; switch (classid) { - case 396: - case 394: - case 392: + case UniqueObjectIds.Diablo_Seal5: + case UniqueObjectIds.Diablo_Seal3: + case UniqueObjectIds.Diablo_Seal1: warn = true; + break; default: warn = false; + break; } for (i = 0; i < 5; i += 1) { - Pather.moveToPreset(me.area, 2, classid, classid === 394 ? 5 : 2, classid === 394 ? 5 : 0); + Pather.moveToPreset(me.area, UnitType.Object, classid, classid === UniqueObjectIds.Diablo_Seal3 ? 5 : 2, classid === UniqueObjectIds.Diablo_Seal3 ? 5 : 0); - seal = getUnit(2, classid); + seal = getUnit(UnitType.Object, classid); if (!seal) { return false; @@ -69,10 +108,10 @@ function Diablo() { warn = false; seal.interact(); - delay(classid === 394 ? 1000 : 500); + delay(classid === UniqueObjectIds.Diablo_Seal3 ? 1000 : 500); if (!seal.mode) { - if (classid === 394 && Attack.validSpot(seal.x + 15, seal.y)) { // de seis optimization + if (classid === UniqueObjectIds.Diablo_Seal3 && 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); @@ -87,15 +126,59 @@ function Diablo() { return false; }; + this.chaosPreattack = function (name, amount) { + var i, n, target, positions; + + switch (me.classid) { + case ClassID.Amazon: + break; + case ClassID.Sorceress: + break; + case ClassID.Necromancer: + break; + case ClassID.Paladin: + 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 ClassID.Barbarian: + break; + case ClassID.Druid: + break; + case ClassID.Assassin: + break; + } + }; + this.getBoss = function (name) { var i, boss, - glow = getUnit(2, 131); + glow = getUnit(UnitType.Object, UniqueObjectIds.Vile_Dog_Afterglow); - for (i = 0; i < (name === getLocaleString(2853) ? 12 : 10); i += 1) { - boss = getUnit(1, name); + for (i = 0; i < 16; i += 1) { + boss = getUnit(UnitType.NPC, name); if (boss) { - return Attack.clear(40, 0, name); + this.chaosPreattack(name, 8); + + return Attack.clear(40, 0, name, this.sort); } delay(250); @@ -106,9 +189,9 @@ function Diablo() { this.vizierSeal = function () { print("Viz layout " + this.vizLayout); - this.followPath(this.vizLayout === 1 ? this.starToVizA : this.starToVizB, this.starSort); + this.followPath(this.vizLayout === 1 ? this.starToVizA : this.starToVizB); - if (!this.openSeal(395) || !this.openSeal(396)) { + if (!this.openSeal(UniqueObjectIds.Diablo_Seal4) || !this.openSeal(UniqueObjectIds.Diablo_Seal5)) { throw new Error("Failed to open Vizier seals."); } @@ -127,9 +210,9 @@ function Diablo() { this.seisSeal = function () { print("Seis layout " + this.seisLayout); - this.followPath(this.seisLayout === 1 ? this.starToSeisA : this.starToSeisB, this.starSort); + this.followPath(this.seisLayout === 1 ? this.starToSeisA : this.starToSeisB); - if (!this.openSeal(394)) { + if (!this.openSeal(UniqueObjectIds.Diablo_Seal3)) { throw new Error("Failed to open de Seis seal."); } @@ -148,9 +231,9 @@ function Diablo() { this.infectorSeal = function () { print("Inf layout " + this.infLayout); - this.followPath(this.infLayout === 1 ? this.starToInfA : this.starToInfB, this.starSort); + this.followPath(this.infLayout === 1 ? this.starToInfA : this.starToInfB); - if (!this.openSeal(392)) { + if (!this.openSeal(UniqueObjectIds.Diablo_Seal1)) { throw new Error("Failed to open Infector seals."); } @@ -163,8 +246,8 @@ function Diablo() { if (!this.getBoss(getLocaleString(2853))) { throw new Error("Failed to kill Infector"); } - - if (!this.openSeal(393)) { + + if (!this.openSeal(UniqueObjectIds.Diablo_Seal2)) { throw new Error("Failed to open Infector seals."); } @@ -175,12 +258,12 @@ function Diablo() { var trapCheck, tick = getTickCount(); - while (getTickCount() - tick < 17500) { + while (getTickCount() - tick < 30000) { if (getTickCount() - tick >= 8000) { switch (me.classid) { - case 1: // Sorceress - if ([56, 59, 64].indexOf(Config.AttackSkill[1]) > -1) { - if (me.getState(121)) { + case ClassID.Sorceress: // Sorceress + if ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard, Skills.Sorceress.Frozen_Orb].indexOf(Config.AttackSkill[1]) > -1) { + if (me.getState(States.SKILLDELAY)) { delay(500); } else { Skill.cast(Config.AttackSkill[1], 0, 7793, 5293); @@ -192,13 +275,13 @@ function Diablo() { delay(500); break; - case 3: // Paladin + case ClassID.Paladin: // Paladin Skill.setSkill(Config.AttackSkill[2]); Skill.cast(Config.AttackSkill[1], 1); break; - case 5: // Druid - if (Config.AttackSkill[1] === 245) { + case ClassID.Druid: // Druid + if (Config.AttackSkill[1] === Skills.Druid.Tornado) { Skill.cast(Config.AttackSkill[1], 0, 7793, 5293); break; @@ -207,7 +290,7 @@ function Diablo() { delay(500); break; - case 6: // Assassin + case ClassID.Assassin: // Assassin if (Config.UseTraps) { trapCheck = ClassAttack.checkTraps({x: 7793, y: 5293}); @@ -223,12 +306,14 @@ function Diablo() { break; default: delay(500); + + break; } } else { delay(500); } - if (getUnit(1, 243)) { + if (getUnit(UnitType.NPC, UnitClassID.diablo)) { return true; } } @@ -236,17 +321,94 @@ function Diablo() { throw new Error("Diablo not found"); }; - this.followPath = function (path, sortfunc) { + this.followPath = function (path) { var i; for (i = 0; i < path.length; i += 2) { - Pather.moveTo(path[i], path[i + 1]); - Attack.clear(30, 0, false, sortfunc); + 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(UnitType.NPC); + + 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.defendPlayers = function () { + var player, + oldPos = {x: me.x, y: me.y}, + monster = getUnit(UnitType.NPC); + + if (monster) { + do { + if (Attack.checkMonster(monster)) { + player = getUnit(UnitType.Player); + + 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, 7774, 5305]; + 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]; this.starToVizB = [7759, 5295, 7734, 5295, 7716, 5295, 7701, 5315, 7666, 5313, 7653, 5284]; this.starToSeisA = [7781, 5259, 7805, 5258, 7802, 5237, 7776, 5228, 7775, 5205, 7804, 5193, 7814, 5169, 7788, 5153]; @@ -256,9 +418,13 @@ function Diablo() { // start Town.doChores(); - Pather.useWaypoint(107); + Pather.useWaypoint(Config.RandomPrecast ? "random" : 107); Precast.doPrecast(true); + if (me.area !== Areas.Act4.River_Of_Flame) { + Pather.useWaypoint(Areas.Act4.River_Of_Flame); + } + if (!Pather.moveTo(7790, 5544)) { throw new Error("Failed to move to Chaos Sanctuary"); } @@ -266,28 +432,54 @@ function Diablo() { this.initLayout(); if (Config.Diablo.Entrance) { - Attack.clear(35, 0, false, this.entranceSort); + Attack.clear(30, 0, false, this.sort); + Pather.moveTo(7790, 5544); + + if (Config.PublicMode) { + Pather.makePortal(); + say(Config.Diablo.EntranceTP); + } + Pather.moveTo(7790, 5544); - Pather.makePortal(); - say(Config.Diablo.EntranceTP); Precast.doPrecast(true); - this.followPath(this.entranceToStar, this.entranceSort); + Attack.clear(30, 0, false, this.sort); + this.followPath(this.entranceToStar); } else { Pather.moveTo(7774, 5305); - Attack.clear(15, 0, false, this.starSort); + Attack.clear(15, 0, false, this.sort); } - Pather.moveTo(7774, 5305); - Pather.makePortal(); - say(Config.Diablo.StarTP); - Attack.clear(30, 0, false, this.starSort); + Pather.moveTo(7791, 5293); + + if (Config.PublicMode) { + Pather.makePortal(); + say(Config.Diablo.StarTP); + } + + Attack.clear(30, 0, false, this.sort); this.vizierSeal(); this.seisSeal(); Precast.doPrecast(true); this.infectorSeal(); - Pather.moveTo(7788, 5292); + + switch (me.classid) { + case ClassID.Sorceress: + Pather.moveTo(7792, 5294); + + break; + default: + Pather.moveTo(7788, 5292); + + break; + } + + + if (Config.PublicMode) { + say(Config.Diablo.DiabloMsg); + } + this.diabloPrep(); - Attack.kill(243); // Diablo + Attack.kill(UnitClassID.diablo); // Diablo Pickit.pickItems(); return true; diff --git a/d2bs/kolbot/libs/bots/DiabloHelper.js b/d2bs/kolbot/libs/bots/DiabloHelper.js index 6a57bb300..56de8ae25 100644 --- a/d2bs/kolbot/libs/bots/DiabloHelper.js +++ b/d2bs/kolbot/libs/bots/DiabloHelper.js @@ -5,21 +5,58 @@ */ function DiabloHelper() { - // sort functions - this.entranceSort = function (a, b) { - return getDistance(a.x, a.y, 7790, 5544) - getDistance(b.x, b.y, 7790, 5544); - }; + // 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) { + return -1; + } + + return 1; + } + + // Vizier + if (me.x < 7765) { + if (a.x > b.x) { + return -1; + } - this.starSort = function (a, b) { - return getDistance(a.x, a.y, 7774, 5305) - getDistance(b.x, b.y, 7774, 5305); + return 1; + } + + // Infector + if (me.x > 7825) { + if (!checkCollision(me, a, 0x1) && a.x < b.x) { + return -1; + } + + return 1; + } + + return getDistance(me, a) - getDistance(me, b); }; // general functions this.getLayout = function (seal, value) { - var sealPreset = getPresetUnit(108, 2, seal); + var sealPreset = getPresetUnit(Areas.Act4.Chaos_Sanctuary, UnitType.Object, 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) { @@ -30,9 +67,9 @@ function DiabloHelper() { }; this.initLayout = function () { - this.vizLayout = this.getLayout(396, 5275); // 1 = "Y", 2 = "L" - this.seisLayout = this.getLayout(394, 7773); // 1= "2", 2 = "5" - this.infLayout = this.getLayout(392, 7893); // 1 = "I", 2 = "J" + this.vizLayout = this.getLayout(UniqueObjectIds.Diablo_Seal5, 5275); // 1 = "Y", 2 = "L" + this.seisLayout = this.getLayout(UniqueObjectIds.Diablo_Seal3, 7773); // 1 = "2", 2 = "5" + this.infLayout = this.getLayout(UniqueObjectIds.Diablo_Seal1, 7893); // 1 = "I", 2 = "J" }; this.getBoss = function (name) { @@ -43,18 +80,18 @@ function DiabloHelper() { delay(500); } - glow = getUnit(2, 131); + glow = getUnit(UnitType.Object, UniqueObjectIds.Vile_Dog_Afterglow); if (glow) { break; } } - for (i = 0; i < (name === getLocaleString(2853) ? 12 : 10); i += 1) { + for (i = 0; i < 16; i += 1) { boss = getUnit(1, name); if (boss) { - return Attack.clear(40, 0, name); + return Attack.clear(40, 0, name, this.sort); } delay(250); @@ -64,35 +101,62 @@ function DiabloHelper() { }; this.vizierSeal = function () { - this.followPath(this.vizLayout === 1 ? this.starToVizA : this.starToVizB, this.starSort); - this.vizLayout === 1 ? Pather.moveTo(7691, 5292) : Pather.moveTo(7695, 5316); + this.followPath(this.vizLayout === 1 ? this.starToVizA : this.starToVizB, this.sort); + + if (this.vizLayout === 1) { + Pather.moveTo(7691, 5292); + } else { + Pather.moveTo(7695, 5316); + } if (!this.getBoss(getLocaleString(2851))) { throw new Error("Failed to kill Vizier"); } + if (Config.FieldID) { + Town.fieldID(); + } + return true; }; this.seisSeal = function () { - this.followPath(this.seisLayout === 1 ? this.starToSeisA : this.starToSeisB, this.starSort); - this.seisLayout === 1 ? Pather.moveTo(7790, 5200) : Pather.moveTo(7798, 5186); + this.followPath(this.seisLayout === 1 ? this.starToSeisA : this.starToSeisB, this.sort); + + 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"); } + if (Config.FieldID) { + Town.fieldID(); + } + return true; }; this.infectorSeal = function () { - this.followPath(this.infLayout === 1 ? this.starToInfA : this.starToInfB, this.starSort); - this.infLayout === 1 ? Pather.moveTo(7908, 5269) : Pather.moveTo(7932, 5305); + this.followPath(this.infLayout === 1 ? this.starToInfA : this.starToInfB, this.sort); + + if (this.infLayout === 1) { + delay(1); + } else { + Pather.moveTo(7928, 5295); // temp + } if (!this.getBoss(getLocaleString(2853))) { throw new Error("Failed to kill Infector"); } + if (Config.FieldID) { + Town.fieldID(); + } + return true; }; @@ -100,30 +164,30 @@ function DiabloHelper() { var trapCheck, tick = getTickCount(); - while (getTickCount() - tick < 17500) { + while (getTickCount() - tick < 30000) { 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); - } + case ClassID.Sorceress: // Sorceress + if ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard, Skills.Sorceress.Frozen_Orb].indexOf(Config.AttackSkill[1]) > -1) { + if (me.getState(States.SKILLDELAY)) { + delay(500); + } else { + Skill.cast(Config.AttackSkill[1], 0, 7793, 5293); + } - break; + break; } delay(500); break; - case 3: // Paladin + case ClassID.Paladin: // Paladin Skill.setSkill(Config.AttackSkill[2]); Skill.cast(Config.AttackSkill[1], 1); break; - case 5: // Druid - if (Config.AttackSkill[1] === 245) { + case ClassID.Druid: // Druid + if (Config.AttackSkill[1] === Skills.Druid.Tornado) { Skill.cast(Config.AttackSkill[1], 0, 7793, 5293); break; @@ -132,12 +196,12 @@ function DiabloHelper() { delay(500); break; - case 6: // Assassin + case ClassID.Assassin: // Assassin if (Config.UseTraps) { trapCheck = ClassAttack.checkTraps({x: 7793, y: 5293}); if (trapCheck) { - ClassAttack.placeTraps({x: 7793, y: 5293, classid: 243}, trapCheck); + ClassAttack.placeTraps({ x: 7793, y: 5293, classid: UnitClassID.diablo}, trapCheck); break; } @@ -148,12 +212,14 @@ function DiabloHelper() { break; default: delay(500); + + break; } } else { delay(500); } - if (getUnit(1, 243)) { + if (getUnit(UnitType.NPC, UnitClassID.diablo)) { return true; } } @@ -193,42 +259,93 @@ function DiabloHelper() { } switch (me.classid) { - case 1: - if ([56, 59, 64].indexOf(Config.AttackSkill[1]) > -1) { - if (me.getState(121)) { + case ClassID.Sorceress: + if ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard, Skills.Sorceress.Frozen_Orb].indexOf(Config.AttackSkill[1]) > -1) { + if (me.getState(States.SKILLDELAY)) { delay(500); } else { Skill.cast(Config.AttackSkill[1], 0, coords[0], coords[1]); } + + return true; } - return true; - case 3: break; - case 6: + case ClassID.Paladin: + break; + case ClassID.Assassin: if (Config.UseTraps) { trapCheck = ClassAttack.checkTraps({x: coords[0], y: coords[1]}); if (trapCheck) { ClassAttack.placeTraps({x: coords[0], y: coords[1]}, 5); + + return true; } } - return true; + break; } return false; }; - this.followPath = function (path, sortfunc) { + this.followPath = function (path) { var i; for (i = 0; i < path.length; i += 2) { - Pather.moveTo(path[i], path[i + 1]); - Attack.clear(30, 0, false, sortfunc); + 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]; @@ -238,47 +355,127 @@ 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; + var i, party; // start Town.doChores(); - Pather.useWaypoint(107); - Precast.doPrecast(true); - Pather.useWaypoint(103); - Town.move("portalspot"); - for (i = 0; i < 120; i += 1) { - if (Pather.usePortal(108, null)) { - break; + 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()); + } + + delay(1000); } - delay(1000); + party = getParty(); + + if (party) { + do { + if (party.area === Areas.Act5.Throne_Of_Destruction || party.area === Areas.Act5.The_Worldstone_Chamber) { // Player is in Throne of Destruction or Worldstone Chamber + return false; // End script + } + } while (party.getNext()); + } } - if (i === 120) { - throw new Error("No portals to Chaos"); + Pather.useWaypoint(Config.RandomPrecast ? "random" : Areas.Act4.River_Of_Flame); + Precast.doPrecast(true); + + if (Config.DiabloHelper.SkipTP) { + if (me.area !== Areas.Act4.River_Of_Flame) { + Pather.useWaypoint(Areas.Act4.River_Of_Flame); + } + + if (!Pather.moveTo(7790, 5544)) { + throw new Error("Failed to move to Chaos Sanctuary"); + } + + if (!Config.DiabloHelper.Entrance) { + Pather.moveTo(7774, 5305); + } + +CSLoop: + for (i = 0; i < Config.DiabloHelper.Wait; i += 1) { + party = getParty(); + + if (party) { + do { + if (party.name !== me.name && party.area === Areas.Act4.Chaos_Sanctuary && (!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(Areas.Act4.The_Pandemonium_Fortress); + Town.move("portalspot"); + + for (i = 0; i < Config.DiabloHelper.Wait; i += 1) { + if (Pather.getPortal(Areas.Act4.Chaos_Sanctuary, Config.Leader || null) && Pather.usePortal(Areas.Act4.Chaos_Sanctuary, 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(); if (Config.DiabloHelper.Entrance) { - Attack.clear(35, 0, false, this.entranceSort); - this.followPath(this.entranceToStar, this.entranceSort); + Attack.clear(35, 0, false, this.sort); + this.followPath(this.entranceToStar); } else { Pather.moveTo(7774, 5305); - Attack.clear(35, 0, false, this.starSort); + Attack.clear(35, 0, false, this.sort); } Pather.moveTo(7774, 5305); - Attack.clear(35, 0, false, this.starSort); + Attack.clear(35, 0, false, this.sort); this.vizierSeal(); this.seisSeal(); Precast.doPrecast(true); this.infectorSeal(); - Pather.moveTo(7788, 5292); + + switch (me.classid) { + case ClassID.Sorceress: + Pather.moveTo(7793, 5291); + + break; + default: + Pather.moveTo(7788, 5292); + + break; + } + this.diabloPrep(); - Attack.kill(243); // Diablo + Attack.kill(UnitClassID.diablo); // Diablo Pickit.pickItems(); return true; -} \ No newline at end of file +} diff --git a/d2bs/kolbot/libs/bots/Duriel.js b/d2bs/kolbot/libs/bots/Duriel.js index 252f03f5a..e3bc0c2a8 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() { 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 (!Pather.useUnit(2, 100, 73)) { throw new Error("Failed to move to Duriel"); } 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(UnitType.NPC, UnitClassID.duriel); if (target) { break; } delay(500); } if (!target) { throw new Error("Duriel not found."); } if (Config.MFLeader) { Pather.makePortal(); say("kill " + UnitClassID.duriel); } 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(Areas.Act2.Canyon_Of_The_Magi); 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, UnitType.Object, UniqueObjectIds.Holder_For_Horadric_Staff, -11, 3)) { throw new Error("Failed to move to Orifice"); } for (i = 0; i < 10; i += 1) { if (getUnit(UnitType.Object, UniqueObjectIds.Portal_To_Duriel)) { break; } delay(500); } if (me.gametype === GameType.Expansion && me.classid !== ClassID.Sorceress) { Attack.clear(5); } unit = getUnit(UnitType.Object, UniqueObjectIds.Portal_To_Duriel); if (unit) { for (i = 0; i < 3; i += 1) { if (me.area === unit.area) { Skill.cast(Skills.Sorceress.Telekinesis, 0, unit); } if (me.area === Areas.Act2.Duriels_Lair) { break; } } } if (me.area !== Areas.Act2.Duriels_Lair && !Pather.useUnit(UnitType.Object, UniqueObjectIds.Portal_To_Duriel, Areas.Act2.Duriels_Lair)) { Attack.clear(10); Pather.useUnit(UnitType.Object, UniqueObjectIds.Portal_To_Duriel, Areas.Act2.Duriels_Lair); } if (me.area !== Areas.Act2.Duriels_Lair) { throw new Error("Failed to move to Duriel"); } if (me.classid === ClassID.Sorceress && me.gametype === GameType.Classic) { this.killDuriel(); } else { Attack.kill(UnitClassID.duriel); // Duriel } Pickit.pickItems(); return true; } \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/Eldritch.js b/d2bs/kolbot/libs/bots/Eldritch.js index 838b51983..43ba0839b 100644 --- a/d2bs/kolbot/libs/bots/Eldritch.js +++ b/d2bs/kolbot/libs/bots/Eldritch.js @@ -8,18 +8,18 @@ function Eldritch() { var chest; Town.doChores(); - Pather.useWaypoint(111); + Pather.useWaypoint(Areas.Act5.Frigid_Highlands); Precast.doPrecast(true); Pather.moveTo(3745, 5084); Attack.clear(15, 0, getLocaleString(22500)); // Eldritch the Rectifier if (Config.Eldritch.OpenChest) { - chest = getPresetUnit(me.area, 2, 455); + chest = getPresetUnit(me.area, UnitType.Object, UniqueObjectIds.Special_Chest); if (chest) { Pather.moveToUnit(chest); - chest = getUnit(2, 455); + chest = getUnit(UnitType.Object, UniqueObjectIds.Special_Chest); if (Misc.openChest(chest)) { Pickit.pickItems(); diff --git a/d2bs/kolbot/libs/bots/Enchant.js b/d2bs/kolbot/libs/bots/Enchant.js index 35e9ce031..912310f71 100644 --- a/d2bs/kolbot/libs/bots/Enchant.js +++ b/d2bs/kolbot/libs/bots/Enchant.js @@ -1,45 +1,683 @@ /** * @filename Enchant.js * @author kolton -* @desc Enchant other players on command +* @desc Enchant other players, open cow portal and give waypoints on command */ function Enchant() { - Town.doChores(); - Pather.useWaypoint(35); - Pather.makePortal(false); + var command, hostile, nick, spot, tick, s, m, + startTime = getTickCount(), + shitList = [], + greet = []; + + this.enchant = function (nick) { + if (!Misc.inMyParty(nick)) { + say("Accept party invite, noob."); + + return false; + } + + var partyUnit, + unit = getUnit(UnitType.Player, nick); + + if (getDistance(me, unit) > 35) { + say("Get closer."); + + return false; + } + + if (!unit) { + partyUnit = getParty(nick); + + // wait until party area is readable? + + if ([Areas.Act2.Lut_Gholein, Areas.Act3.Kurast_Docktown, Areas.Act4.The_Pandemonium_Fortress, Areas.Act5.Harrogath].indexOf(partyUnit.area) > -1) { + say("Wait for me at waypoint."); + Town.goToTown([Areas.Act1.Rogue_Encampment, Areas.Act2.Lut_Gholein, Areas.Act3.Kurast_Docktown, Areas.Act4.The_Pandemonium_Fortress, Areas.Act5.Harrogath].indexOf(partyUnit.area) + 1); // index+1 for town 2,3,4,5 + + unit = getUnit(UnitType.Player, 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(Skills.Sorceress.Enchant, 0); + sendPacket(1, 0x11, 4, unit.type, 4, unit.gid); + delay(500); + } + } while (unit.getNext()); + } else { + say("Couldn't find you, champ."); + } + + unit = getUnit(UnitType.NPC); + + if (unit) { + do { + if (unit.getParent() && unit.getParent().name === nick) { // merc or any other owned unit + Skill.setSkill(Skills.Sorceress.Enchant, 0); + sendPacket(1, 0x11, 4, unit.type, 4, unit.gid); + delay(500); + } + } while (unit.getNext()); + } + + return true; + }; + + this.autoChant = function () { + var unit, + chanted = []; + + // Player + unit = getUnit(UnitType.Player); + + if (unit) { + do { + if (unit.name !== me.name && !unit.dead && shitList.indexOf(unit.name) === -1 && Misc.inMyParty(unit.name) && !unit.getState(States.ENCHANT) && getDistance(me, unit) <= 40) { + Skill.setSkill(Skills.Sorceress.Enchant, 0); + sendPacket(1, 0x11, 4, unit.type, 4, unit.gid); + delay(500); + chanted.push(unit.name); + } + } while (unit.getNext()); + } + + // Minion + unit = getUnit(1); + + if (unit) { + do { + if (unit.getParent() && chanted.indexOf(unit.getParent().name) > -1 && !unit.getState(States.ENCHANT) && getDistance(me, unit) <= 40) { + Skill.setSkill(Skills.Sorceress.Enchant, 0); + sendPacket(1, 0x11, 4, unit.type, 4, unit.gid); + delay(500); + } + } while (unit.getNext()); + } + + return true; + }; + + this.getLeg = function () { + var i, portal, wirt, leg, gid, wrongLeg; + + if (me.getItem(ItemClassIds.Wirts_Leg)) { + return me.getItem(ItemClassIds.Wirts_Leg); + } + + if (!Config.Enchant.GetLeg) { + leg = getUnit(UnitType.Item, ItemClassIds.Wirts_Leg); + + if (leg) { + do { + if (leg.name.indexOf("ÿc1") > -1) { + wrongLeg = true; + } else if (getDistance(me, leg) <= 15) { + gid = leg.gid; + + Pickit.pickItem(leg); + + return me.getItem(-1, -1, gid); + } + } while (leg.getNext()); + } + + say("Bring the leg " + (wrongLeg ? "from this difficulty" : "") + " close to me."); + + return false; + } + + Pather.useWaypoint(Areas.Act1.Stony_Field); + Precast.doPrecast(true); + Pather.moveToPreset(me.area, UnitType.NPC, SuperUniques.Rakanishu, 8, 8); + + for (i = 0; i < 6; i += 1) { + portal = Pather.getPortal(Areas.Act1.Tristram); + + if (portal) { + Pather.usePortal(null, null, portal); + + break; + } + + delay(500); + } + + if (!portal) { + say("Failed to enter Tristram :("); + Town.goToTown(); + + return false; + } + + Pather.moveTo(25048, 5177); + + wirt = getUnit(UnitType.Object, UniqueObjectIds.Wirts_Body); + + for (i = 0; i < 8; i += 1) { + wirt.interact(); + delay(500); + + leg = getUnit(UnitType.Item, ItemClassIds.Wirts_Leg); + + if (leg) { + gid = leg.gid; + + Pickit.pickItem(leg); + Town.goToTown(); + + return me.getItem(-1, -1, gid); + } + } + + Town.goToTown(); + say("Failed to get the leg :("); + + return false; + }; + + this.getTome = function () { + var tome, akara, myTome; + + myTome = me.findItem("tbk", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory); + 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(UnitType.NPC, NPC.Akara); + + if (!akara || akara.area !== me.area || getDistance(me, akara) > 20) { + say("Akara not found."); + + return false; + } + + myTome = me.findItem("tbk", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory); + tome = me.getItem("tbk"); + + if (tome) { + do { + if (!myTome || tome.gid !== myTome.gid) { + return copyUnit(tome); + } + } while (tome.getNext()); + } + + akara = Town.initNPC("Shop"); + + if (!akara) { + say("Failed to buy tome :("); + + return false; + } + + tome = akara.getItem("tbk"); + + if (tome.buy()) { + tome = me.getItem("tbk"); + + if (tome) { + do { + if (!myTome || tome.gid !== myTome.gid) { + return copyUnit(tome); + } + } while (tome.getNext()); + } + } + + return false; + }; + + this.openPortal = function (nick) { + if (!Misc.inMyParty(nick)) { + say("Accept party invite, noob."); + + return true; + } + + if (Pather.getPortal(Areas.Act1.Moo_Moo_Farm)) { + say("Cow portal already open."); + + return true; + } + + if (me.getQuest(Quests.Act1.The_Search_for_Cain, 10)) { // king dead or cain not saved + say("Can't open the portal because I killed Cow King."); + + return false; + } + + if (Config.Enchant.GetLeg && !me.getQuest(Quests.Act1.The_Search_for_Cain, 0)) { + say("Can't get leg because I don't have Cain quest."); + + return false; + } + + switch (me.gametype) { + case GameType.Classic: // classic + if (!me.getQuest(Quests.Act4.Terrors_End, 0)) { // diablo not completed + say("I don't have Diablo quest."); + + return false; + } + + break; + case GameType.Expansion: // expansion + if (!me.getQuest(Quests.Act5.Eve_of_Destruction, 0)) { // baal not completed + say("I don't have Baal quest."); + + return false; + } + + break; + } + + var i, leg, tome; + + leg = this.getLeg(); + + if (!leg) { + return false; + } + + tome = this.getTome(); + + if (!tome) { + return false; + } + + if (!Town.openStash() || !Cubing.emptyCube() || !Storage.Cube.MoveTo(leg) || !Storage.Cube.MoveTo(tome) || !Cubing.openCube()) { + return false; + } + + transmute(); + delay(500); + + for (i = 0; i < 10; i += 1) { + if (Pather.getPortal(Areas.Act1.Moo_Moo_Farm)) { + return true; + } + + delay(200); + } + + say("Failed to open cow portal."); + + return false; + }; + + this.getWpNick = function (nick) { + if (!this.wpNicks) { + this.wpNicks = {}; + } + + if (this.wpNicks.hasOwnProperty(nick)) { + if (this.wpNicks[nick].requests > 4) { + return "maxrequests"; + } + + if (getTickCount() - this.wpNicks[nick].timer < 60000) { + return "mintime"; + } + + return true; + } + + return false; + }; + + this.addWpNick = function (nick) { + this.wpNicks[nick] = {timer: getTickCount(), requests: 0}; + }; + + this.giveWps = function (nick) { + if (!Misc.inMyParty(nick)) { + say("Accept party invite, noob."); + + return false; + } + + var i, act, timeout, wpList; + + switch (this.getWpNick(nick)) { + case "maxrequests": + say(nick + ", you have spent all your waypoint requests for this game."); + + return false; + case "mintime": + say(nick + ", you may request waypoints every 60 seconds."); + + return false; + case false: + this.addWpNick(nick); + + break; + } + + act = this.getPlayerAct(nick); + + switch (act) { + case 1: + wpList = [Areas.Act1.Cold_Plains, Areas.Act1.Stony_Field, Areas.Act1.Dark_Wood, Areas.Act1.Black_Marsh, Areas.Act1.Outer_Cloister, Areas.Act1.Jail_Level_1, Areas.Act1.Inner_Cloister, Areas.Act1.Catacombs_Level_2]; + + break; + case 2: + wpList = [Areas.Act2.A2_Sewers_Level_2, Areas.Act2.Dry_Hills, Areas.Act2.Halls_Of_The_Dead_Level_2, Areas.Act2.Far_Oasis, Areas.Act2.Lost_City, Areas.Act2.Palace_Cellar_Level_1, Areas.Act2.Arcane_Sanctuary, Areas.Act2.Canyon_Of_The_Magi]; + + break; + case 3: + wpList = [Areas.Act3.Spider_Forest, Areas.Act3.Great_Marsh, Areas.Act3.Flayer_Jungle, Areas.Act3.Lower_Kurast, Areas.Act3.Kurast_Bazaar, Areas.Act3.Upper_Kurast, Areas.Act3.Travincal, Areas.Act3.Durance_Of_Hate_Level_2]; + + break; + case 4: + wpList = [Areas.Act4.City_Of_The_Damned, Areas.Act4.River_Of_Flame]; + + break; + case 5: + wpList = [Areas.Act5.Frigid_Highlands, Areas.Act5.Arreat_Plateau, Areas.Act5.Crystalized_Passage, Areas.Act5.Glacial_Trail, Areas.Act5.Halls_Of_Pain, Areas.Act5.Frozen_Tundra, Areas.Act5.Ancients_Way, Areas.Act5.The_Worldstone_Keep_Level_2]; + + break; + } + +MainLoop: + for (i = 0; i < wpList.length; i += 1) { + if (this.checkHostiles()) { + break; + } + + try { + Pather.useWaypoint(wpList[i], true); + Pather.makePortal(); + say(getArea().name + " TP up"); + + for (timeout = 0; timeout < 20; timeout += 1) { + if (getUnit(0, nick)) { + break; + } + + delay(1000); + } + + if (timeout >= 20) { + say("Aborting wp giving."); + + break MainLoop; + } + + delay(5000); + } catch (error) { + + } + } + + Town.doChores(); + Town.goToTown(1); + Town.move("portalspot"); + + this.wpNicks[nick].requests += 1; + this.wpNicks[nick].timer = getTickCount(); + + return true; + }; + + this.getPlayerAct = function (name) { + var unit = getParty(); + + if (unit) { + do { + if (unit.name === name) { + if (unit.area <= Areas.Act1.Moo_Moo_Farm) { + return 1; + } + + if (unit.area >= Areas.Act2.Lut_Gholein && unit.area <= Areas.Act2.Arcane_Sanctuary) { + return 2; + } + + if (unit.area >= Areas.Act3.Kurast_Docktown && unit.area <= Areas.Act3.Durance_Of_Hate_Level_3) { + return 3; + } + + if (unit.area >= Areas.Act4.The_Pandemonium_Fortress && unit.area <= Areas.Act4.Chaos_Sanctuary) { + return 4; + } + + return 5; + } + } while (unit.getNext()); + } + + return false; + }; + + this.checkHostiles = function () { + var rval = false, + party = getParty(); + + if (party) { + do { + if (party.name !== me.name && getPlayerFlag(me.gid, party.gid, 8)) { + rval = true; + + if (Config.ShitList && shitList.indexOf(party.name) === -1) { + shitList.push(party.name); + } + } + } while (party.getNext()); + } + + 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; + }; - var chant; - function ChatEvent(nick, msg) { - if (msg === Config.Enchant.Trigger) { - chant = true; + command = [msg, nick]; + } + + function GreetEvent(mode, param1, param2, name1, name2) { + switch (mode) { + case 0x02: + if (me.inTown && me.mode === PlayerModes.Town_Neutral) { // idle in town + greet.push(name1); + } + + break; } } + // START + if (Config.ShitList) { + shitList = ShitList.read(); + } + addEventListener("chatmsg", ChatEvent); + addEventListener("gameevent", GreetEvent); + Town.doChores(); + Town.goToTown(1); + Town.move("portalspot"); + + spot = { + x: me.x, + y: me.y + }; while (true) { - if (chant) { - var player = getUnit(0); + while (greet.length > 0) { + nick = greet.shift(); - do { - if (player.name !== me.name && getDistance(me, player) <= 20) { - Skill.cast(52, 0, player); - delay(200); + if (shitList.indexOf(nick) === -1) { + say("Welcome, " + nick + "! For a list of commands say 'help'"); + } + } + + 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(); + + if (shitList.indexOf(command[1]) > -1) { + say("No " + command[0] + " for the shitlisted."); + + break; + } + + say("Commands:"); + 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] : "")); + + 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(); + + if (shitList.indexOf(command[1]) > -1) { + say("No chant for the shitlisted."); + + break; + } + + this.enchant(command[1]); + + break; + case Config.Enchant.Triggers[1].toLowerCase(): // cows + hostile = this.checkHostiles(); + + if (shitList.indexOf(command[1]) > -1) { + say("No cows for the shitlisted."); + + break; } - } while (player.getNext()); - chant = false; + this.openPortal(command[1]); + me.cancel(); + + break; + case Config.Enchant.Triggers[2].toLowerCase(): // wps + hostile = this.checkHostiles(); + + if (shitList.indexOf(command[1]) > -1) { + say("No waypoints for the shitlisted."); + + break; + } + + if (hostile) { + say("Command disabled because of hostiles."); + + break; + } + + this.giveWps(command[1]); + + break; + } } - if (getTickCount() - me.gamestarttime >= Config.Enchant.GameLength * 1e6) { - say("Next Game!"); + command = ""; + + if (me.act > 1) { + Town.goToTown(1); + } + + if (Config.Enchant.AutoChant) { + this.autoChant(); + } + + if (getTickCount() - startTime >= Config.Enchant.GameLength * 6e4) { + say("Use kolbot or die!"); + delay(1000); break; } - delay(500); + delay(200); } return true; diff --git a/d2bs/kolbot/libs/bots/Endugu.js b/d2bs/kolbot/libs/bots/Endugu.js index 4c256ab0f..9c817d5a3 100644 --- a/d2bs/kolbot/libs/bots/Endugu.js +++ b/d2bs/kolbot/libs/bots/Endugu.js @@ -6,10 +6,10 @@ function Endugu() { Town.doChores(); - Pather.useWaypoint(78); + Pather.useWaypoint(Areas.Act3.Flayer_Jungle); Precast.doPrecast(true); - if (!Pather.moveToExit([88, 89, 91], true) || !Pather.moveToPreset(me.area, 2, 406)) { + if (!Pather.moveToExit([Areas.Act3.Flayer_Dungeon_Level_1, Areas.Act3.Flayer_Dungeon_Level_2, Areas.Act3.Flayer_Dungeon_Level_3], true) || !Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Khalim_Chest2)) { throw new Error("Failed to move to Endugu"); } diff --git a/d2bs/kolbot/libs/bots/Eyeback.js b/d2bs/kolbot/libs/bots/Eyeback.js index 4c8cf0bde..6565a389c 100644 --- a/d2bs/kolbot/libs/bots/Eyeback.js +++ b/d2bs/kolbot/libs/bots/Eyeback.js @@ -6,10 +6,10 @@ function Eyeback() { Town.doChores(); - Pather.useWaypoint(112); + Pather.useWaypoint(Areas.Act5.Arreat_Plateau); Precast.doPrecast(true); - if (!Pather.moveToPreset(111, 1, 784, 0, 0, false, true)) { + if (!Pather.moveToPreset(Areas.Act5.Frigid_Highlands, UnitType.NPC, SuperUniques.Eyeback_Unleashed)) { throw new Error("Failed to move to Eyeback the Unleashed"); } diff --git a/d2bs/kolbot/libs/bots/FastDiablo.js b/d2bs/kolbot/libs/bots/FastDiablo.js index dd27a792a..ea07e2885 100644 --- a/d2bs/kolbot/libs/bots/FastDiablo.js +++ b/d2bs/kolbot/libs/bots/FastDiablo.js @@ -5,20 +5,65 @@ */ function FastDiablo() { - var i, tick, seal; + this.getLayout = function (seal, value) { + var sealPreset = getPresetUnit(Areas.Act4.Chaos_Sanctuary, UnitType.Object, seal); - this.chaosPreattack = function (name) { + 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(UniqueObjectIds.Diablo_Seal5, 5275); + this.seisLayout = this.getLayout(UniqueObjectIds.Diablo_Seal3, 7773); + this.infLayout = this.getLayout(UniqueObjectIds.Diablo_Seal1, 7893); + }; + + this.getBoss = function (name) { + var i, boss, + glow = getUnit(UnitType.Object, UniqueObjectIds.Vile_Dog_Afterglow); + + for (i = 0; i < 24; i += 1) { + boss = getUnit(1, name); + + if (boss) { + this.chaosPreattack(name, 8); + + try { + Attack.kill(name); + } catch (e) { + Attack.clear(10, 0, name); + } + + Pickit.pickItems(); + + return true; + } + + delay(250); + } + + return !!glow; + }; + + this.chaosPreattack = function (name, amount) { var i, n, target, positions; switch (me.classid) { - case 0: + case ClassID.Amazon: break; - case 1: + case ClassID.Sorceress: break; - case 2: + case ClassID.Necromancer: break; - case 3: - target = getUnit(1, name); + case ClassID.Paladin: + target = getUnit(UnitType.NPC, name); if (!target) { return; @@ -31,7 +76,7 @@ function FastDiablo() { Pather.moveTo(target.x + positions[i][0], target.y + positions[i][1]); Skill.setSkill(Config.AttackSkill[2], 0); - for (n = 0; n < 5; n += 1) { + for (n = 0; n < amount; n += 1) { Skill.cast(Config.AttackSkill[1], 1); } @@ -40,101 +85,172 @@ function FastDiablo() { } break; - case 4: + case ClassID.Barbarian: break; - case 5: + case ClassID.Druid: break; - case 6: + case ClassID.Assassin: break; } }; - this.openSeal = function (id) { - Pather.moveToPreset(108, 2, id, 4); + this.diabloPrep = function () { + var trapCheck, + tick = getTickCount(); + + while (getTickCount() - tick < 20000) { + if (getTickCount() - tick >= 8000) { + switch (me.classid) { + case ClassID.Sorceress: // Sorceress + if ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard, Skills.Sorceress.Frozen_Orb].indexOf(Config.AttackSkill[1]) > -1) { + if (me.getState(States.SKILLDELAY)) { + delay(500); + } else { + Skill.cast(Config.AttackSkill[1], 0, 7793, 5293); + } + + break; + } - seal = getUnit(2, id); + delay(500); - if (seal) { - for (i = 0; i < 3; i += 1) { - seal.interact(); + break; + case ClassID.Paladin: // Paladin + Skill.setSkill(Config.AttackSkill[2]); + Skill.cast(Config.AttackSkill[1], 1); - tick = getTickCount(); + break; + case ClassID.Druid: // Druid + if (Config.AttackSkill[1] === Skills.Druid.Tornado) { + Skill.cast(Config.AttackSkill[1], 0, 7793, 5293); - while (getTickCount() - tick < 500) { - if (seal.mode) { - return true; + break; } - delay(10); + delay(500); + + break; + case ClassID.Assassin: // Assassin + if (Config.UseTraps) { + trapCheck = ClassAttack.checkTraps({ x: 7793, y: 5293 }); + + if (trapCheck) { + ClassAttack.placeTraps({ x: 7793, y: 5293, classid: UnitClassID.diablo }, trapCheck); + + break; + } + } + + delay(500); + + break; + default: + delay(500); } + } else { + delay(500); + } + + if (getUnit(UnitType.NPC, UnitClassID.diablo)) { + return true; } } - return false; + throw new Error("Diablo not found"); }; - Town.doChores(); - Pather.useWaypoint(107); - Precast.doPrecast(true); + this.openSeal = function (classid) { + var i, j, seal; - if (!this.openSeal(395) || !this.openSeal(396)) { - throw new Error("Failed to open seals"); - } + for (i = 0; i < 5; i += 1) { + Pather.moveToPreset(Areas.Act4.Chaos_Sanctuary, UnitType.Object, classid, classid === UniqueObjectIds.Diablo_Seal3 ? 5 : 2, classid === UniqueObjectIds.Diablo_Seal3 ? 5 : 0); - for (i = 0; i < 10; i += 1) { - if (getUnit(1, getLocaleString(2851))) { - break; - } + if (i > 1) { + Attack.clear(10); + } - delay(300); - } + for (j = 0; j < 3; j += 1) { + seal = getUnit(UnitType.Object, classid); - Attack.kill(getLocaleString(2851)); // Grand Vizier of Chaos - Pickit.pickItems(); + if (seal) { + break; + } - if (!this.openSeal(394)) { - throw new Error("Failed to open seals"); - } + delay(100); + } - Pather.moveTo(me.x, me.y + 30); + if (!seal) { + throw new Error("Seal not found (id " + classid + ")"); + } - for (i = 0; i < 10; i += 1) { - if (getUnit(1, getLocaleString(2852))) { - break; + if (seal.mode) { + return true; + } + + sendPacket(1, 0x13, 4, 0x2, 4, seal.gid); + delay(classid === UniqueObjectIds.Diablo_Seal3 ? 1000 : 500); + + if (!seal.mode) { + if (classid === UniqueObjectIds.Diablo_Seal3 && 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; + } } - delay(300); - } + throw new Error("Failed to open seal (id " + classid + ")"); + }; - this.chaosPreattack(getLocaleString(2852)); - Attack.kill(getLocaleString(2852)); // Lord De Seis - Pickit.pickItems(); + Town.doChores(); + Pather.useWaypoint(Areas.Act4.River_Of_Flame); + Precast.doPrecast(true); + this.initLayout(); + this.openSeal(UniqueObjectIds.Diablo_Seal4); + this.openSeal(UniqueObjectIds.Diablo_Seal5); + + if (this.vizLayout === 1) { + Pather.moveTo(7691, 5292); + } else { + Pather.moveTo(7695, 5316); + } - if (!this.openSeal(392) || !this.openSeal(393)) { - throw new Error("Failed to open seals"); + if (!this.getBoss(getLocaleString(2851))) { + throw new Error("Failed to kill Vizier"); } - for (i = 0; i < 10; i += 1) { - if (getUnit(1, getLocaleString(2853))) { // Infector of Souls - break; - } + this.openSeal(UniqueObjectIds.Diablo_Seal3); - delay(300); + if (this.seisLayout === 1) { + Pather.moveTo(7771, 5196); + } else { + Pather.moveTo(7798, 5186); } - Attack.kill(getLocaleString(2853)); // Infector of Souls - Pickit.pickItems(); - Pather.moveTo(7793, 5288); + if (!this.getBoss(getLocaleString(2852))) { + throw new Error("Failed to kill de Seis"); + } - for (i = 0; i < 40; i = i + 1) { - if (getUnit(1, 243)) { - break; - } + this.openSeal(UniqueObjectIds.Diablo_Seal1); + this.openSeal(UniqueObjectIds.Diablo_Seal2); + + if (this.infLayout === 1) { + delay(1); + } else { + Pather.moveTo(7928, 5295); // temp + } - delay(500); + if (!this.getBoss(getLocaleString(2853))) { + throw new Error("Failed to kill Infector"); } - Attack.kill(243); // Diablo + Pather.moveTo(7788, 5292); + this.diabloPrep(); + Attack.kill(UnitClassID.diablo); // Diablo Pickit.pickItems(); return true; diff --git a/d2bs/kolbot/libs/bots/Follower.js b/d2bs/kolbot/libs/bots/Follower.js index 2cc3dc032..345787b2b 100644 --- a/d2bs/kolbot/libs/bots/Follower.js +++ b/d2bs/kolbot/libs/bots/Follower.js @@ -47,7 +47,8 @@ */ function Follower() { - var i, j, stop, leader, leaderUnit, charClass, piece, skill, result, unit, + var i, j, stop, leader, leaderUnit, charClass, piece, skill, result, unit, player, + commanders = [Config.Leader], attack = true, openContainers = true, classes = ["amazon", "sorceress", "necromancer", "paladin", "barbarian", "druid", "assassin"], @@ -70,11 +71,11 @@ function Follower() { // Get leader's Unit this.getLeaderUnit = function (name) { - var player = getUnit(0, name); + var player = getUnit(UnitType.Player, name); if (player) { do { - if (player.mode !== 0 && player.mode !== 17) { + if (!player.dead) { return player; } } while (player.getNext()); @@ -85,13 +86,19 @@ function Follower() { // Get leader's act from Party Unit this.checkLeaderAct = function (unit) { - if (unit.area <= 39) { + if (unit.area <= Areas.Act1.Moo_Moo_Farm) { return 1; - } else if (unit.area >= 40 && unit.area <= 74) { + } + + if (unit.area >= Areas.Act2.Lut_Gholein && unit.area <= Areas.Act2.Arcane_Sanctuary) { return 2; - } else if (unit.area >= 75 && unit.area <= 102) { + } + + if (unit.area >= Areas.Act3.Kurast_Docktown && unit.area <= Areas.Act3.Durance_Of_Hate_Level_3) { return 3; - } else if (unit.area >= 103 && unit.area <= 108) { + } + + if (unit.area >= Areas.Act4.The_Pandemonium_Fortress && unit.area <= Areas.Act4.Chaos_Sanctuary) { return 4; } @@ -114,14 +121,14 @@ function Follower() { } if (unit.inTown) { - target = getUnit(2, "waypoint"); + target = getUnit(UnitType.Object, "waypoint"); if (target && getDistance(me, target) < 20) { return 3; } } - target = getUnit(2, "portal"); + target = getUnit(UnitType.Object, "portal"); if (target) { do { @@ -134,22 +141,22 @@ function Follower() { } // Arcane<->Cellar portal - if ((me.area === 74 && area === 54) || (me.area === 54 && area === 74)) { - Pather.usePortal(area); + if ((me.area === Areas.Act2.Arcane_Sanctuary && area === Areas.Act2.Palace_Cellar_Level_3) || (me.area === Areas.Act2.Palace_Cellar_Level_3 && area === Areas.Act2.Arcane_Sanctuary)) { + Pather.usePortal(null); return 4; } // Tal-Rasha's tomb->Duriel's lair - if (me.area >= 66 && me.area <= 72 && area === 73) { - Pather.useUnit(2, 100, area); + if (me.area >= Areas.Act2.Tal_Rashas_Tomb_1 && me.area <= Areas.Act2.Tal_Rashas_Tomb_7 && area === Areas.Act2.Duriels_Lair) { + Pather.useUnit(UnitType.Object, UniqueObjectIds.Portal_To_Duriel, area); return 4; } // Throne->Chamber - if (me.area === 131 && area === 132) { - target = getUnit(2, 563); + if (me.area === Areas.Act5.Throne_Of_Destruction && area === Areas.Act5.The_Worldstone_Chamber) { + target = getUnit(UnitType.Object, UniqueObjectIds.Worldstone_Chamber); if (target) { Pather.usePortal(null, null, target); @@ -244,28 +251,28 @@ function Follower() { switch (act) { case 2: - if (me.area >= 40) { + if (me.area >= Areas.Act2.Lut_Gholein) { break; } Town.move("warriv"); - npc = getUnit(1, 155); + npc = getUnit(UnitType.NPC, UnitClassID.warriv1); if (npc) { npc.openMenu(); - npc.useMenu(0x0D36); + Misc.useMenu(NPCMenu.Go_East); } break; case 3: - if (me.area >= 75) { + if (me.area >= Areas.Act3.Kurast_Docktown) { break; } Town.move("palace"); - npc = getUnit(1, 201); + npc = getUnit(UnitType.NPC, UnitClassID.jerhyn); if (npc) { npc.openMenu(); @@ -274,23 +281,23 @@ function Follower() { Town.move("meshif"); - npc = getUnit(1, 210); + npc = getUnit(UnitType.NPC, UnitClassID.meshif1); if (npc) { npc.openMenu(); - npc.useMenu(0x0D38); + Misc.useMenu(NPCMenu.Sail_East); } break; case 4: - if (me.area >= 103) { + if (me.area >= Areas.Act4.The_Pandemonium_Fortress) { break; } if (me.inTown) { Town.move("cain"); - npc = getUnit(1, 245); + npc = getUnit(UnitType.NPC, UnitClassID.cain3); if (npc) { npc.openMenu(); @@ -298,12 +305,12 @@ function Follower() { } Town.move("portalspot"); - Pather.usePortal(102, null); + Pather.usePortal(Areas.Act3.Durance_Of_Hate_Level_3, null); } delay(1500); - target = getUnit(2, 342); + target = getUnit(UnitType.Object, UniqueObjectIds.Hellgate); if (target) { Pather.moveTo(target.x - 3, target.y - 1); @@ -313,20 +320,20 @@ function Follower() { break; case 5: - if (me.area >= 109) { + if (me.area >= Areas.Act5.Harrogath) { break; } Town.move("tyrael"); - npc = getUnit(1, "tyrael"); + npc = getUnit(UnitType.NPC, "tyrael"); if (npc) { npc.openMenu(); me.cancel(); try { - Pather.useUnit(2, 566, 109); + Pather.useUnit(UnitType.Object, UniqueObjectIds.Harrogath_LastPortal, Areas.Act5.Harrogath); } catch (a5e) { } @@ -360,7 +367,7 @@ function Follower() { }; this.pickPotions = function (range) { - if (me.mode === 17) { + if (me.dead) { return false; } @@ -372,11 +379,11 @@ function Follower() { var status, pickList = [], - item = getUnit(4); + item = getUnit(UnitType.Item); if (item) { do { - if ((item.mode === 3 || item.mode === 5) && item.itemType >= 76 && item.itemType <= 78 && getDistance(me, item) <= range) { + if ((item.mode === ItemModes.Item_on_ground || item.mode === ItemModes.Item_being_dropped) && item.itemType >= NTItemTypes.healingpotion && item.itemType <= NTItemTypes.rejuvpotion && getDistance(me, item) <= range) { pickList.push(copyUnit(item)); } } while (item.getNext()); @@ -387,21 +394,13 @@ function Follower() { while (pickList.length > 0) { item = pickList.shift(); - if (!item || !copyUnit(item).x) { - continue; - } - - status = Pickit.checkItem(item); - - if (!status) { - continue; - } + if (item && copyUnit(item).x) { + status = Pickit.checkItem(item).result; - if (!Pickit.canPick(item)) { - continue; + if (status && Pickit.canPick(item)) { + Pickit.pickItem(item, status); + } } - - Pickit.pickItem(item, status); } return true; @@ -419,11 +418,11 @@ function Follower() { ox = me.x; oy = me.y; - unit = getUnit(2); + unit = getUnit(UnitType.Object); if (unit) { do { - if (containers.indexOf(unit.name.toLowerCase()) > -1 && unit.mode === 0 && getDistance(me, unit) <= range) { + if (containers.indexOf(unit.name.toLowerCase()) > -1 && unit.mode === ObjectModes.Neutral && getDistance(me, unit) <= range) { unitList.push(copyUnit(unit)); } } while (unit.getNext()); @@ -444,7 +443,7 @@ function Follower() { }; this.chatEvent = function (nick, msg) { - if (msg && nick === Config.Follower.Leader) { + if (msg && nick === Config.Leader) { switch (msg) { case "tele": case me.name + " tele": @@ -485,6 +484,10 @@ function Follower() { say("Attack on."); } + break; + case "flash": + Packet.flash(me.gid); + break; case "aoff": case me.name + " aoff": @@ -519,13 +522,13 @@ function Follower() { break; case "r": - if (me.mode === 17) { + if (me.mode === PlayerModes.Dead) { me.revive(); } break; default: - if (me.classid === 3 && msg.indexOf("aura ") > -1) { + if (me.classid === ClassID.Paladin && msg.indexOf("aura ") > -1) { piece = msg.split(" ")[0]; if (piece === me.name || piece === "all") { @@ -538,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."); } @@ -559,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."); } @@ -573,6 +576,22 @@ function Follower() { break; } } + + if (msg && msg.split(" ")[0] === "leader" && commanders.indexOf(nick) > -1) { + piece = msg.split(" ")[1]; + + if (typeof piece === "string") { + if (commanders.indexOf(piece) === -1) { + commanders.push(piece); + } + + say("Switching leader to " + piece); + + Config.Leader = piece; + leader = this.getLeader(Config.Leader); + leaderUnit = this.getLeaderUnit(Config.Leader); + } + } }; addEventListener("chatmsg", this.chatEvent); @@ -584,7 +603,7 @@ function Follower() { charClass = classes[me.classid]; for (i = 0; i < 20; i += 1) { - leader = this.getLeader(Config.Follower.Leader); + leader = this.getLeader(Config.Leader); if (leader) { break; @@ -601,21 +620,24 @@ function Follower() { say("Leader found."); } - while (!Misc.inMyParty(Config.Follower.Leader)) { + while (!Misc.inMyParty(Config.Leader)) { delay(500); } say("Partied."); - Town.move("portalspot"); + + if (me.inTown) { + Town.move("portalspot"); + } // Main Loop - while (Misc.inMyParty(Config.Follower.Leader)) { - if (me.mode === 17) { + while (Misc.inMyParty(Config.Leader)) { + if (me.mode === PlayerModes.Dead) { while (!me.inTown) { me.revive(); delay(1000); } - + Town.move("portalspot"); say("I'm alive!"); } @@ -626,15 +648,29 @@ function Follower() { if (!me.inTown) { if (!leaderUnit || !copyUnit(leaderUnit).x) { - leaderUnit = this.getLeaderUnit(Config.Follower.Leader); + leaderUnit = this.getLeaderUnit(Config.Leader); if (leaderUnit) { say("Leader unit found."); } } - if (getDistance(me, leaderUnit) <= 50) { - if (getDistance(me, leaderUnit) > 4) { + if (!leaderUnit) { + player = getUnit(UnitType.Player); + + if (player) { + do { + if (player.name !== me.name) { + Pather.moveToUnit(player); + + break; + } + } while (player.getNext()); + } + } + + if (leaderUnit && getDistance(me.x, me.y, leaderUnit.x, leaderUnit.y) <= 60) { + if (getDistance(me.x, me.y, leaderUnit.x, leaderUnit.y) > 4) { Pather.moveToUnit(leaderUnit); } } @@ -649,7 +685,7 @@ function Follower() { } if (leader.area !== me.area && !me.inTown) { - while (leader.area === 0) { + while (leader.area === Areas.None) { delay(100); } @@ -678,20 +714,20 @@ function Follower() { break; } - while (me.area === 0) { + while (me.area === Areas.None) { delay(100); } - leaderUnit = this.getLeaderUnit(Config.Follower.Leader); + leaderUnit = this.getLeaderUnit(Config.Leader); } } switch (action) { case "cow": - if (me.area === 1) { + if (me.area === Areas.Act1.Rogue_Encampment) { Town.move("portalspot"); - if (!Pather.usePortal(39)) { + if (!Pather.usePortal(Areas.Act1.Moo_Moo_Farm)) { say("Failed to use cow portal."); } } @@ -709,7 +745,7 @@ function Follower() { delay(rand(1, 3) * 500); - unit = getUnit(2, "waypoint"); + unit = getUnit(UnitType.Object, "waypoint"); if (unit) { WPLoop: @@ -727,7 +763,7 @@ WPLoop: unit.interact(); } - if (getUIFlag(0x14)) { + if (getUIFlag(UIFlags.waypoint)) { break WPLoop; } @@ -736,7 +772,7 @@ WPLoop: } } - if (getUIFlag(0x14)) { + if (getUIFlag(UIFlags.waypoint)) { say("Got wp."); } else { say("Failed to get wp."); @@ -752,14 +788,14 @@ WPLoop: break; case "p": - say("Picking items."); + say("!Picking items."); Pickit.pickItems(); if (openContainers) { this.openContainers(20); } - say("Done picking."); + say("!Done picking."); break; case "1": @@ -771,9 +807,12 @@ WPLoop: say("Going outside."); Town.goToTown(this.checkLeaderAct(leader)); Town.move("portalspot"); - Pather.usePortal(null, leader.name); - while (!this.getLeaderUnit(Config.Follower.Leader)) { + if (!Pather.usePortal(null, leader.name)) { + break; + } + + while (!this.getLeaderUnit(Config.Leader) && !me.dead) { Attack.clear(10); delay(200); } @@ -796,6 +835,18 @@ WPLoop: say("Ready"); } + break; + case "h": + if (me.classid === ClassID.Barbarian) { + Skill.cast(Skills.Barbarian.Howl); + } + + break; + case "bo": + if (me.classid === ClassID.Barbarian) { + Precast.doPrecast(true); + } + break; case "a2": case "a3": @@ -805,15 +856,15 @@ WPLoop: break; case me.name + " tp": - unit = me.findItem("tbk", 0, 3); + unit = me.findItem("tbk", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory); - if (unit && unit.getStat(70)) { + if (unit && unit.getStat(Stats.quantity)) { unit.interact(); break; } - unit = me.findItem("tsc", 0, 3); + unit = me.findItem("tsc", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory); if (unit) { unit.interact(); diff --git a/d2bs/kolbot/libs/bots/Frozenstein.js b/d2bs/kolbot/libs/bots/Frozenstein.js index bc81e7978..010397c77 100644 --- a/d2bs/kolbot/libs/bots/Frozenstein.js +++ b/d2bs/kolbot/libs/bots/Frozenstein.js @@ -6,10 +6,10 @@ function Frozenstein() { Town.doChores(); - Pather.useWaypoint(113); + Pather.useWaypoint(Areas.Act5.Crystalized_Passage); Precast.doPrecast(true); - if (!Pather.moveToExit(114, true) || !Pather.moveToPreset(me.area, 2, 460, -5, -5)) { + if (!Pather.moveToExit(Areas.Act5.Frozen_River, true) || !Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Drehya_Outside_Town, -5, -5)) { throw new Error("Failed to move to Frozenstein"); } diff --git a/d2bs/kolbot/libs/bots/Gamble.js b/d2bs/kolbot/libs/bots/Gamble.js index 71eeb19c5..1f9020a3e 100644 --- a/d2bs/kolbot/libs/bots/Gamble.js +++ b/d2bs/kolbot/libs/bots/Gamble.js @@ -6,19 +6,23 @@ function Gamble() { var gold, + info = Gambling.getInfo(), needGold = false; + if (!info) { + throw new Error("Bad Gambling System config."); + } + me.maxgametime = 0; Town.goToTown(1); addEventListener('copydata', function (mode, msg) { - if (needGold && mode === 0 && Gambling.goldFinders.indexOf(msg) > -1) { - print("got game request from " + msg); + if (needGold && mode === 0 && info.goldFinders.indexOf(msg) > -1) { + print("Got game request from " + msg); sendCopyData(null, msg, 4, me.gamename + "/" + me.gamepassword); } - } - ); + }); while (true) { if (Town.needGamble()) { @@ -31,21 +35,22 @@ function Gamble() { while (needGold) { while (true) { - gold = getUnit(4, 523, 3); + if (Town.needGamble()) { + needGold = false; + } + + Town.stash(); - if (!gold) { + gold = getUnit(UnitType.Item, ItemClassIds.Gold, 3); + + if (!gold || !Pickit.canPick(gold)) { break; } Pickit.pickItem(gold); - Town.stash(); delay(500); - - if (Town.needGamble()) { - needGold = false; - } } - + delay(500); } diff --git a/d2bs/kolbot/libs/bots/GetKeys.js b/d2bs/kolbot/libs/bots/GetKeys.js new file mode 100644 index 000000000..2ee0bc450 --- /dev/null +++ b/d2bs/kolbot/libs/bots/GetKeys.js @@ -0,0 +1,48 @@ +function GetKeys() { + Town.doChores(); + + if (!me.findItems("pk1") || me.findItems("pk1").length < 3) { + try { + print("ÿc2Countess"); + Pather.useWaypoint(Areas.Act1.Black_Marsh); + Precast.doPrecast(true); + Pather.journeyTo(Areas.Act1.Tower_Cellar_Level_5); + Pather.moveToPreset(me.area, UnitType.Object, 580); + Attack.kill(getLocaleString(2875)); + Pickit.pickItems(); + } catch (countessError) { + print("ÿc1Countess failed"); + } + } + + if (!me.findItems("pk2") || me.findItems("pk2").length < 3) { + try { + print("ÿc2Summoner"); + Town.goToTown(); + Town.doChores(); + Pather.useWaypoint(Areas.Act2.Arcane_Sanctuary); + Precast.doPrecast(true); + Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Horazons_Journal, -3, -3); + Attack.kill(UnitClassID.summoner); + Pickit.pickItems(); + } catch (summonerError) { + print("ÿc1Summoner failed"); + } + } + + if (!me.findItems("pk3") || me.findItems("pk3").length < 3) { + try { + print("ÿc2Nihlathak"); + Town.goToTown(); + Town.doChores(); + Pather.useWaypoint(Areas.Act5.Halls_Of_Pain); + Precast.doPrecast(true); + Pather.moveToExit(Areas.Act5.Halls_Of_Vaught, true); + Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Nihlathak_Outside_Town); + Attack.kill(UnitClassID.nihlathakboss); + Pickit.pickItems(); + } catch (nihlathakError) { + print("ÿc1Nihlathak failed"); + } + } +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/GhostBusters.js b/d2bs/kolbot/libs/bots/GhostBusters.js index 216adbe40..0bf515926 100644 --- a/d2bs/kolbot/libs/bots/GhostBusters.js +++ b/d2bs/kolbot/libs/bots/GhostBusters.js @@ -34,7 +34,9 @@ function GhostBusters() { if (monster) { do { - if ([38, 39, 40, 41, 42, 631, 632, 633].indexOf(monster.classid) > -1 && getDistance(me, monster) <= 30 && Attack.checkMonster(monster)) { + if ([UnitClassID.wraith1, UnitClassID.wraith2, UnitClassID.wraith3, UnitClassID.wraith4, UnitClassID.wraith5, UnitClassID.wraith6, + UnitClassID.wraith7, UnitClassID.wraith8].indexOf(monster.classid) > -1 && getDistance(me, monster) <= 30 && Attack.checkMonster(monster)) { + monList.push(copyUnit(monster)); } } while (monster.getNext()); @@ -46,18 +48,16 @@ function GhostBusters() { } } - CollMap.reset(); - return true; }; this.cellar = function () { // black marsh wp var i; - Pather.useWaypoint(6); + Pather.useWaypoint(Areas.Act1.Black_Marsh); Precast.doPrecast(true); - for (i = 20; i <= 25; i += 1) { + for (i = Areas.Act1.Forgotten_Tower; i <= Areas.Act1.Tower_Cellar_Level_5; i += 1) { Pather.moveToExit(i, true); this.clearGhosts(); } @@ -68,10 +68,10 @@ function GhostBusters() { this.jail = function () { // gonna use inner cloister wp and travel backwards var i; - Pather.useWaypoint(32); + Pather.useWaypoint(Areas.Act1.Inner_Cloister); Precast.doPrecast(true); - for (i = 31; i >= 29; i -= 1) { + for (i = Areas.Act1.Jail_Level_3; i >= Areas.Act1.Jail_Level_1; i -= 1) { Pather.moveToExit(i, true); this.clearGhosts(); } @@ -80,9 +80,9 @@ function GhostBusters() { }; this.cathedral = function () { // inner cloister wp - Pather.useWaypoint(32); + Pather.useWaypoint(Areas.Act1.Inner_Cloister); Precast.doPrecast(true); - Pather.moveToExit(33, true); + Pather.moveToExit(Areas.Act1.Cathedral, true); this.clearGhosts(); return true; @@ -91,22 +91,22 @@ function GhostBusters() { this.tombs = function () { // canyon wp var i; - Pather.useWaypoint(46); + Pather.useWaypoint(Areas.Act2.Canyon_Of_The_Magi); Precast.doPrecast(true); - for (i = 66; i <= 72; i += 1) { + for (i = Areas.Act2.Tal_Rashas_Tomb_1; i <= Areas.Act2.Tal_Rashas_Tomb_7; i += 1) { Pather.moveToExit(i, true); this.clearGhosts(); - Pather.moveToExit(46, true); + Pather.moveToExit(Areas.Act2.Canyon_Of_The_Magi, true); } return true; }; this.flayerDungeon = function () { // flayer jungle wp - var areas = [88, 89, 91]; + var areas = [Areas.Act3.Flayer_Dungeon_Level_1, Areas.Act3.Flayer_Dungeon_Level_2, Areas.Act3.Flayer_Dungeon_Level_3]; - Pather.useWaypoint(78); + Pather.useWaypoint(Areas.Act3.Flayer_Jungle); Precast.doPrecast(true); while (areas.length) { @@ -118,29 +118,29 @@ function GhostBusters() { }; this.crystalinePassage = function () { // crystaline passage wp - Pather.useWaypoint(113); + Pather.useWaypoint(Areas.Act5.Crystalized_Passage); Precast.doPrecast(true); this.clearGhosts(); - Pather.moveToExit(114, true); // frozen river + Pather.moveToExit(Areas.Act5.Frozen_River, true); // frozen river this.clearGhosts(); return true; }; this.glacialTrail = function () { // glacial trail wp - Pather.useWaypoint(115); + Pather.useWaypoint(Areas.Act5.Glacial_Trail); Precast.doPrecast(true); this.clearGhosts(); - Pather.moveToExit(116, true); // drifter + Pather.moveToExit(Areas.Act5.Drifter_Cavern, true); // drifter this.clearGhosts(); return true; }; this.icyCellar = function () { // glacial trail wp - Pather.useWaypoint(118); + Pather.useWaypoint(Areas.Act5.Ancients_Way); Precast.doPrecast(true); - Pather.moveToExit(119, true); // drifter + Pather.moveToExit(Areas.Act5.Icy_Cellar, true); // drifter this.clearGhosts(); return true; diff --git a/d2bs/kolbot/libs/bots/Hephasto.js b/d2bs/kolbot/libs/bots/Hephasto.js index 072f528bc..c3b0e1c43 100644 --- a/d2bs/kolbot/libs/bots/Hephasto.js +++ b/d2bs/kolbot/libs/bots/Hephasto.js @@ -6,10 +6,10 @@ function Hephasto() { Town.doChores(); - Pather.useWaypoint(107); + Pather.useWaypoint(Areas.Act4.River_Of_Flame); Precast.doPrecast(true); - if (!Pather.moveToPreset(me.area, 2, 376)) { + if (!Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Forge_Hell)) { throw new Error("Failed to move to Hephasto"); } diff --git a/d2bs/kolbot/libs/bots/IPHunter.js b/d2bs/kolbot/libs/bots/IPHunter.js index e99a16b2b..b669e0064 100644 --- a/d2bs/kolbot/libs/bots/IPHunter.js +++ b/d2bs/kolbot/libs/bots/IPHunter.js @@ -5,7 +5,7 @@ */ function IPHunter() { - var ip = me.gameserverip.split(".")[3]; + var ip = Number(me.gameserverip.split(".")[3]); if (Config.IPHunter.IPList.indexOf(ip) > -1) { print("IP found!"); diff --git a/d2bs/kolbot/libs/bots/Icehawk.js b/d2bs/kolbot/libs/bots/Icehawk.js index 9408c959d..e0ab06774 100644 --- a/d2bs/kolbot/libs/bots/Icehawk.js +++ b/d2bs/kolbot/libs/bots/Icehawk.js @@ -6,10 +6,10 @@ function Icehawk() { Town.doChores(); - Pather.useWaypoint(80); + Pather.useWaypoint(Areas.Act3.Kurast_Bazaar); Precast.doPrecast(true); - if (!Pather.moveToExit([92, 93], false)) { + if (!Pather.moveToExit([Areas.Act3.A3_Sewers_Level_1, Areas.Act3.A3_Sewers_Level_2], false)) { throw new Error("Failed to move to Icehawk"); } diff --git a/d2bs/kolbot/libs/bots/Izual.js b/d2bs/kolbot/libs/bots/Izual.js index 57fc4b518..83e1f3f05 100644 --- a/d2bs/kolbot/libs/bots/Izual.js +++ b/d2bs/kolbot/libs/bots/Izual.js @@ -6,14 +6,14 @@ function Izual() { Town.doChores(); - Pather.useWaypoint(106); + Pather.useWaypoint(Areas.Act4.City_Of_The_Damned); Precast.doPrecast(true); - if (!Pather.moveToPreset(105, 1, 256)) { + if (!Pather.moveToPreset(Areas.Act4.Plains_Of_Despair, UnitType.NPC, UnitClassID.izual)) { throw new Error("Failed to move to Izual."); } - Attack.kill(256); // Izual + Attack.kill(UnitClassID.izual); // Izual Pickit.pickItems(); return true; diff --git a/d2bs/kolbot/libs/bots/KillDclone.js b/d2bs/kolbot/libs/bots/KillDclone.js new file mode 100644 index 000000000..0bef026a3 --- /dev/null +++ b/d2bs/kolbot/libs/bots/KillDclone.js @@ -0,0 +1,24 @@ +/** +* @filename KillDclone.js +* @author kolton +* @desc Got to Palace Cellar level 3 and kill Diablo Clone. +*/ + +function KillDclone() { + //Town.doChores(); + Pather.useWaypoint(Areas.Act2.Arcane_Sanctuary); + Precast.doPrecast(true); + + if (!Pather.usePortal(null)) { + throw new Error("Failed to move to Palace Cellar"); + } + + Attack.kill(UnitClassID.diabloclone); + Pickit.pickItems(); + + if (AutoMule.getInfo() && AutoMule.getInfo().hasOwnProperty("torchMuleInfo")) { + scriptBroadcast("muleAnni"); + } + + return true; +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/KurastChests.js b/d2bs/kolbot/libs/bots/KurastChests.js deleted file mode 100644 index a8e524a81..000000000 --- a/d2bs/kolbot/libs/bots/KurastChests.js +++ /dev/null @@ -1,48 +0,0 @@ -/** -* @filename KurastChests.js -* @author kolton -* @desc open chests in Lower Kurast and optionally Kurast Bazaar -*/ - -function KurastChests() { - Town.doChores(); - - if (Config.KurastChests.LowerKurast) { - Pather.useWaypoint(79); - Precast.doPrecast(true); - Misc.openChestsInArea(79); - } - - if (Config.KurastChests.Bazaar) { - if (me.inTown) { - Pather.useWaypoint(80); - Precast.doPrecast(true); - } - - Misc.openChestsInArea(80); - } - - if (Config.KurastChests.Sewers1) { - if (me.inTown) { - Pather.useWaypoint(80); - Precast.doPrecast(true); - } - - Pather.moveToExit(me.area === 80 ? 92 : [80, 92], true); - Misc.openChestsInArea(92); - } - - if (Config.KurastChests.Sewers2) { - if (me.inTown) { - Pather.useWaypoint(80); - Precast.doPrecast(true); - } - - Pather.moveToExit(me.area === 92 ? 93 : me.area === 80 ? [92, 93] : [80, 92, 93], true); - Misc.openChestsInArea(93); - } - - Town.goToTown(4); - - return true; -} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/KurastTemples.js b/d2bs/kolbot/libs/bots/KurastTemples.js index d47f4b058..815796a4d 100644 --- a/d2bs/kolbot/libs/bots/KurastTemples.js +++ b/d2bs/kolbot/libs/bots/KurastTemples.js @@ -6,14 +6,14 @@ function KurastTemples() { Town.doChores(); - Pather.useWaypoint(80); + Pather.useWaypoint(Areas.Act3.Kurast_Bazaar); Precast.doPrecast(true); var i, - areas = [94, 95, 96, 97, 98, 99]; + areas = [Areas.Act3.Ruined_Temple, Areas.Act3.Disused_Fane, Areas.Act3.Forgotten_Reliquary, Areas.Act3.Forgotten_Temple, Areas.Act3.Ruined_Fane, Areas.Act3.Disused_Reliquary]; for (i = 0; i < 6; i += 1) { - if (me.area !== 80 + Math.floor(i / 2)) { + if (me.area !== Areas.Act3.Kurast_Bazaar + Math.floor(i / 2)) { if (!Pather.moveToExit(80 + Math.floor(i / 2), true)) { throw new Error("Failed to change area"); } diff --git a/d2bs/kolbot/libs/bots/MFHelper.js b/d2bs/kolbot/libs/bots/MFHelper.js index 3770fcf28..e554ee7ae 100644 --- a/d2bs/kolbot/libs/bots/MFHelper.js +++ b/d2bs/kolbot/libs/bots/MFHelper.js @@ -1,18 +1,41 @@ +/** +* @filename MFHelper.js +* @author kolton +* @desc help another player kill bosses or clear areas +*/ + function MFHelper() { - var player, playerAct, split, + var i, player, playerAct, split, area, oldCommand = "", command = ""; - function ChatEvent(who, msg) { - command = msg; + function ChatEvent(name, msg) { + if (!player) { + var i, + match = ["kill", "clearlevel", "clear", "quit", "cows", "council"]; + + if (msg) { + for (i = 0; i < match.length; i += 1) { + if (msg.match(match[i])) { + player = this.findPlayer(name); + + break; + } + } + } + } + + if (player && name === player.name) { + command = msg; + } } - - this.findPlayer = function () { + + this.findPlayer = function (name) { var party = getParty(); if (party) { do { - if (party.name !== me.name && !party.inTown) { + if (party.name !== me.name && party.name === name) { return party; } } while (party.getNext()); @@ -22,113 +45,283 @@ function MFHelper() { }; this.getPlayerAct = function (player) { - switch (true) { - case player.area > 0 && player.area <= 39: + if (player.area > Areas.None && player.area <= Areas.Act1.Moo_Moo_Farm) { return 1; - case player.area >= 40 && player.area <= 74: + } + + if (player.area >= Areas.Act2.Lut_Gholein && player.area <= Areas.Act2.Arcane_Sanctuary) { return 2; - case player.area >= 75 && player.area <= 102: + } + + if (player.area >= Areas.Act3.Kurast_Docktown && player.area <= Areas.Act3.Durance_Of_Hate_Level_3) { return 3; - case player.area >= 103 && player.area <= 108: + } + + if (player.area >= Areas.Act4.The_Pandemonium_Fortress && player.area <= Areas.Act4.Chaos_Sanctuary) { return 4; - case player.area >= 109: + } + + if (player.area >= Areas.Act5.Harrogath) { return 5; } return false; }; + this.buildCowRooms = function () { + var i, j, room, kingPreset, badRooms, badRooms2, + finalRooms = [], + indexes = []; + + kingPreset = getPresetUnit(me.area, UnitType.NPC, SuperUniques.The_Cow_King); + badRooms = getRoom(kingPreset.roomx * 5 + kingPreset.x, kingPreset.roomy * 5 + kingPreset.y).getNearby(); + + for (i = 0; i < badRooms.length; i += 1) { + badRooms2 = badRooms[i].getNearby(); + + for (j = 0; j < badRooms2.length; j += 1) { + if (indexes.indexOf(badRooms2[j].x.toString() + badRooms2[j].y.toString()) === -1) { + indexes.push(badRooms2[j].x.toString() + badRooms2[j].y.toString()); + } + } + } + + room = getRoom(); + + do { + if (indexes.indexOf(room.x.toString() + room.y.toString()) === -1) { + finalRooms.push([room.x * 5 + room.xsize / 2, room.y * 5 + room.ysize / 2]); + } + } while (room.getNext()); + + return finalRooms; + }; + + this.clearCowLevel = function () { + var room, result, myRoom, + rooms = this.buildCowRooms(); + + function RoomSort(a, b) { + return getDistance(myRoom[0], myRoom[1], a[0], a[1]) - getDistance(myRoom[0], myRoom[1], b[0], b[1]); + } + + while (rooms.length > 0) { + // get the first room + initialize myRoom var + if (!myRoom) { + room = getRoom(me.x, me.y); + } + + if (room) { + if (room instanceof Array) { // use previous room to calculate distance + myRoom = [room[0], room[1]]; + } else { // create a new room to calculate distance (first room, done only once) + myRoom = [room.x * 5 + room.xsize / 2, room.y * 5 + room.ysize / 2]; + } + } + + rooms.sort(RoomSort); + room = rooms.shift(); + + result = Pather.getNearestWalkable(room[0], room[1], 10, 2); + + if (result) { + Pather.moveTo(result[0], result[1], 3); + + if (!Attack.clear(30)) { + return false; + } + } + } + + return true; + }; + addEventListener("chatmsg", ChatEvent); Town.doChores(); Town.move("portalspot"); -MainLoop: - while (true) { - if (!player) { - player = this.findPlayer(); + if (Config.Leader) { + for (i = 0; i < 30; i += 1) { + if (Misc.inMyParty(Config.Leader)) { + break; + } + + delay(1000); } + if (i === 30) { + throw new Error("MFHelper: Leader not partied"); + } + + player = this.findPlayer(Config.Leader); + } + + // START +MainLoop: + while (true) { if (player) { + while (!player.area) { + delay(100); + } + playerAct = this.getPlayerAct(player); - + if (playerAct && playerAct !== me.act) { - Town.goToTown(this.getPlayerAct(player)); + Town.goToTown(playerAct); Town.move("portalspot"); } - } - if (command !== oldCommand) { - oldCommand = command; + // Finish if leader is in chaos or throne + if ([Areas.Act4.Chaos_Sanctuary, Areas.Act5.Throne_Of_Destruction].indexOf(player.area) > -1) { + break; + } + + if (command !== oldCommand) { + oldCommand = command; + + if (command.indexOf("kill") > -1) { + print("ÿc4MFHelperÿc0: Kill"); - switch (true) { - case command.indexOf("kill") > -1: - print("Received command: kill"); - delay(500); + split = command.split("kill ")[1]; + area = player.area; - split = command.split("kill ")[1]; - - Pather.usePortal(player.area, player.name); - Precast.doPrecast(false); + for (i = 0; i < 5; i += 1) { + if (Pather.usePortal(player.area, player.name)) { + break; + } - try { - if (!!parseInt(split, 10)) { - split = parseInt(split, 10); + delay(1000); } - Attack.kill(split); - Pickit.pickItems(); - } catch (killerror) { - print(killerror); - } + if (me.area === area) { + Precast.doPrecast(false); - delay(1000); + try { + if (!!parseInt(split, 10)) { + split = parseInt(split, 10); + } - if (!me.inTown && !Pather.usePortal(null, player.name)) { - Town.goToTown(); - } + Attack.kill(split); + Pickit.pickItems(); + } catch (killerror) { + print(killerror); + } - break; - case command.indexOf("clearlevel") > -1: - print("Received command: clearlevel"); - delay(500); - Pather.usePortal(player.area, player.name); - Precast.doPrecast(false); - Attack.clearLevel(Config.ClearType); - delay(1000); - - if (!Pather.usePortal(null, player.name)) { - Town.goToTown(); - } + delay(1000); - break; - case command.indexOf("clear") > -1: - print("Received command: clear"); - delay(500); + if (!me.inTown && !Pather.usePortal(null, player.name)) { + Town.goToTown(); + } + } else { + print("Failed to use portal."); + } + } else if (command.indexOf("clearlevel") > -1) { + print("ÿc4MFHelperÿc0: Clear Level"); - split = command.split("clear ")[1] + area = player.area; - Pather.usePortal(player.area, player.name); - Precast.doPrecast(false); + for (i = 0; i < 5; i += 1) { + if (Pather.usePortal(player.area, player.name)) { + break; + } - try { - if (!!parseInt(split, 10)) { - split = parseInt(split, 10); + delay(1000); } - Attack.clear(15, 0, split); - } catch (killerror) { - print(killerror); - } + if (me.area === area) { + Precast.doPrecast(false); + Attack.clearLevel(Config.ClearType); + Precast.doPrecast(true); - delay(1000); + if (!Pather.usePortal(null, player.name)) { + Town.goToTown(); + } + } else { + print("Failed to use portal."); + } + } else if (command.indexOf("clear") > -1) { + print("ÿc4MFHelperÿc0: Clear"); - if (!me.inTown && !Pather.usePortal(null, player.name)) { - Town.goToTown(); - } + split = command.split("clear ")[1]; + area = player.area; - break; - case command.indexOf("quit") > -1: - break MainLoop; + for (i = 0; i < 5; i += 1) { + if (Pather.usePortal(player.area, player.name)) { + break; + } + + delay(1000); + } + + if (me.area === area) { + Precast.doPrecast(false); + + try { + if (!!parseInt(split, 10)) { + split = parseInt(split, 10); + } + + Attack.clear(15, 0, split); + } catch (killerror2) { + print(killerror2); + } + + delay(1000); + + if (!me.inTown && !Pather.usePortal(null, player.name)) { + Town.goToTown(); + } + } else { + print("Failed to use portal."); + } + } else if (command.indexOf("quit") > -1) { + break MainLoop; + } else if (command.indexOf("cows") > -1) { + print("ÿc4MFHelperÿc0: Clear Cows"); + + for (i = 0; i < 5; i += 1) { + if (Town.goToTown(1) && Pather.usePortal(Areas.Act1.Moo_Moo_Farm)) { + break; + } + + delay(1000); + } + + if (me.area === Areas.Act1.Moo_Moo_Farm) { + Precast.doPrecast(false); + this.clearCowLevel(); + delay(1000); + + if (!Pather.usePortal(null, player.name)) { + Town.goToTown(); + } + } else { + print("Failed to use portal."); + } + } else if (command.indexOf("council") > -1) { + print("ÿc4MFHelperÿc0: Kill Council"); + + area = player.area; + + for (i = 0; i < 5; i += 1) { + if (Pather.usePortal(player.area, player.name)) { + break; + } + + delay(1000); + } + + if (me.area === area) { + Precast.doPrecast(false); + Attack.clearList(Attack.getMob([UnitClassID.councilmember1, UnitClassID.councilmember2, UnitClassID.councilmember3], 0, 40)); + + if (!Pather.usePortal(null, player.name)) { + Town.goToTown(); + } + } else { + print("Failed to use portal."); + } + } } } diff --git a/d2bs/kolbot/libs/bots/Mausoleum.js b/d2bs/kolbot/libs/bots/Mausoleum.js index 76e3eb07f..88855d030 100644 --- a/d2bs/kolbot/libs/bots/Mausoleum.js +++ b/d2bs/kolbot/libs/bots/Mausoleum.js @@ -6,20 +6,20 @@ function Mausoleum() { Town.doChores(); - Pather.useWaypoint(3); + Pather.useWaypoint(Areas.Act1.Cold_Plains); Precast.doPrecast(true); - if (!Pather.moveToExit(17, true)) { + if (!Pather.moveToExit(Areas.Act1.Burial_Grounds, true)) { throw new Error("Failed to move to Burial Grounds"); } if (Config.Mausoleum.KillBloodRaven) { - Pather.moveToPreset(17, 1, 805); + Pather.moveToPreset(Areas.Act1.Burial_Grounds, UnitType.NPC, 805); Attack.kill(getLocaleString(3111)); // Blood Raven Pickit.pickItems(); } - if (!Pather.moveToExit(19, true)) { + if (!Pather.moveToExit(Areas.Act1.Mausoleum, true)) { throw new Error("Failed to move to Mausoleum"); } @@ -27,7 +27,7 @@ function Mausoleum() { if (Config.Mausoleum.ClearCrypt) { // Crypt exit is... awkward - if (!(Pather.moveToExit(17, true) && Pather.moveToPreset(17, 5, 6, 5, 0) && Pather.moveToExit(18, true))) { + if (!(Pather.moveToExit(Areas.Act1.Burial_Grounds, true) && Pather.moveToPreset(Areas.Act1.Burial_Grounds, UnitType.Warp, 6, 5, 0) && Pather.moveToExit(Areas.Act1.Crypt, true))) { throw new Error("Failed to move to Crypt"); } diff --git a/d2bs/kolbot/libs/bots/Mephisto.js b/d2bs/kolbot/libs/bots/Mephisto.js index 58aa0e2fb..6eef9ce8d 100644 --- a/d2bs/kolbot/libs/bots/Mephisto.js +++ b/d2bs/kolbot/libs/bots/Mephisto.js @@ -1,6 +1,6 @@ /** * @filename Mephisto.js -* @author kolton +* @author kolton, njomnjomnjom * @desc kill Mephisto */ @@ -9,7 +9,7 @@ function Mephisto() { var i, angle, angles, pos = {}, attackCount = 0, - meph = getUnit(1, 242); + meph = getUnit(UnitType.NPC, UnitClassID.mephisto); if (!meph) { throw new Error("Mephisto not found!"); @@ -22,11 +22,11 @@ function Mephisto() { while (attackCount < 300 && Attack.checkMonster(meph)) { //if (getUnit(3, 276)) { - if (meph.mode === 5) { + if (meph.mode === NPCModes.attack2) { //if (attackCount % 2 === 0) { angle = Math.round(Math.atan2(me.y - meph.y, me.x - meph.x) * 180 / Math.PI); angles = me.y > meph.y ? [-30, -60, -90] : [30, 60, 90]; - + for (i = 0; i < angles.length; i += 1) { //pos.dist = Math.round(getDistance(me, meph)); pos.dist = 18; @@ -49,7 +49,7 @@ function Mephisto() { attackCount += 1; } - return (meph.mode === 0 || meph.mode === 12); + return (meph.mode === NPCModes.death || meph.mode === NPCModes.dead); }; this.moat = function () { @@ -60,7 +60,7 @@ function Mephisto() { delay(350); Pather.moveTo(17563, 8072); - mephisto = getUnit(1, 242); + mephisto = getUnit(UnitType.NPC, UnitClassID.mephisto); if (!mephisto) { throw new Error("Mephisto not found."); @@ -112,31 +112,72 @@ function Mephisto() { return true; }; + this.killCouncil = function () { + var i, + coords = [17600, 8125, 17600, 8015, 17643, 8068]; + + for (i = 0; i < coords.length; i += 2) { + Pather.moveTo(coords[i], coords[i + 1]); + + if (Config.MFLeader) { + Pather.makePortal(); + say("council " + i); + } + + Attack.clearList(Attack.getMob([UnitClassID.councilmember1, UnitClassID.councilmember2, UnitClassID.councilmember3], 0, 40)); + } + + return true; + }; + Town.doChores(); - Pather.useWaypoint(101); + Pather.useWaypoint(Areas.Act3.Durance_Of_Hate_Level_2); Precast.doPrecast(true); - if (!Pather.moveToExit(102, true)) { + if (!Pather.moveToExit(Areas.Act3.Durance_Of_Hate_Level_3, true)) { throw new Error("Failed to move to Durance Level 3"); } + if (Config.Mephisto.KillCouncil) { + this.killCouncil(); + } + Pather.moveTo(17566, 8069); - if (me.classid === 1) { + if (me.classid === ClassID.Sorceress) { if (Config.Mephisto.MoatTrick) { this.moat(); - Attack.kill(242); // Mephisto + + Skill.usePvpRange = true; + + Attack.kill(UnitClassID.mephisto); // Mephisto + + Skill.usePvpRange = false; } else { - this.killMephisto(); + //this.killMephisto(); + Attack.kill(UnitClassID.mephisto); // Mephisto } } else { - Attack.kill(242); // Mephisto + Attack.kill(UnitClassID.mephisto); // Mephisto } Pickit.pickItems(); - /*Pather.moveTo(17590, 8068); - delay(1500); - Pather.usePortal(null);*/ + + if (Config.OpenChests) { + Pather.moveTo(17572, 8011); + Attack.openChests(5); + Pather.moveTo(17572, 8125); + Attack.openChests(5); + Pather.moveTo(17515, 8061); + Attack.openChests(5); + } + + if (Config.Mephisto.TakeRedPortal) { + Pather.moveTo(17590, 8068); + delay(1500); + Pather.moveTo(17601, 8070); + Pather.usePortal(null); + } return true; -} \ No newline at end of file +} diff --git a/d2bs/kolbot/libs/bots/Nihlathak.js b/d2bs/kolbot/libs/bots/Nihlathak.js index a142e44fb..0a10d6bd9 100644 --- a/d2bs/kolbot/libs/bots/Nihlathak.js +++ b/d2bs/kolbot/libs/bots/Nihlathak.js @@ -6,22 +6,22 @@ function Nihlathak() { Town.doChores(); - Pather.useWaypoint(123); + Pather.useWaypoint(Areas.Act5.Halls_Of_Pain); Precast.doPrecast(false); - if (!Pather.moveToExit(124, true)) { + if (!Pather.moveToExit(Areas.Act5.Halls_Of_Vaught, true)) { throw new Error("Failed to go to Nihlathak"); } - Pather.moveToPreset(me.area, 2, 462, 0, 0, false, true); + Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Nihlathak_Outside_Town, 0, 0, false, true); - if (Config.Nihlathak.ViperQuit && getUnit(1, 597)) { + if (Config.Nihlathak.ViperQuit && getUnit(UnitType.NPC, UnitClassID.clawviper9)) { print("Tomb Vipers found."); return true; } - Attack.kill(526); // Nihlathak + Attack.kill(UnitClassID.nihlathakboss); // Nihlathak Pickit.pickItems(); return true; diff --git a/d2bs/kolbot/libs/bots/OrgTorch.js b/d2bs/kolbot/libs/bots/OrgTorch.js new file mode 100644 index 000000000..4e31894bc --- /dev/null +++ b/d2bs/kolbot/libs/bots/OrgTorch.js @@ -0,0 +1,464 @@ +/** +* @filename OrgTorch.js +* @author kolton +* @desc Convert keys to organs and organs to torches. It can work with TorchSystem to get keys from other characters +* @notes Search for the word "Start" and follow the comments if you want to know what this script does and when. +*/ + +function OrgTorch() { + this.doneAreas = []; + + // Identify & mule + this.checkTorch = function () { + if (me.area === Areas.UberLevels.Tristram) { + Pather.moveTo(25105, 5140); + Pather.usePortal(Areas.Act5.Harrogath); + } + + Town.doChores(); + + if (!Config.OrgTorch.MakeTorch) { + return false; + } + + var item = me.getItem("cm2"); + + if (item) { + do { + if (item.quality === ItemQuality.Unique && Pickit.checkItem(item).result === 1) { + if (AutoMule.getInfo() && AutoMule.getInfo().hasOwnProperty("torchMuleInfo")) { + scriptBroadcast("muleTorch"); + //quit(); + scriptBroadcast("quit"); + //delay(10000); + } + + return true; + } + } while (item.getNext()); + } + + return false; + }; + + // Check whether the killer is alone in the game + this.aloneInGame = function () { + var party = getParty(); + + if (party) { + do { + if (party.name !== me.name) { + return false; + } + } while (party.getNext()); + } + + return true; + }; + + // Try to lure a monster - wait until it's close enough + this.lure = function (bossId) { + var tick, + unit = getUnit(UnitType.NPC, bossId); + + if (unit) { + tick = getTickCount(); + + while (getTickCount() - tick < 2000) { + if (getDistance(me, unit) <= 10) { + return true; + } + + delay(50); + } + } + + return false; + }; + + // Check if we have complete sets of organs + this.completeSetCheck = function () { + var horns = me.findItems("dhn"), + brains = me.findItems("mbr"), + eyes = me.findItems("bey"); + + if (!horns || !brains || !eyes) { + return false; + } + + // We just need one set to make a torch + if (Config.OrgTorch.MakeTorch) { + return horns.length && brains.length && eyes.length; + } + + return horns.length === brains.length && horns.length === eyes.length && brains.length === eyes.length; + }; + + // Get fade in River of Flames + this.getFade = function () { + if (Config.OrgTorch.GetFade && me.classid === ClassID.Paladin) { + if (!me.getState(States.FADE)) { + print("Getting Fade"); + Pather.useWaypoint(Areas.Act4.River_Of_Flame); + Precast.doPrecast(true); + Pather.moveTo(7811, 5872); + + if (me.classid === ClassID.Paladin && me.getSkill(Skills.Paladin.Salvation, 1)) { + Skill.setSkill(Skills.Paladin.Salvation, 0); + } + + while (!me.getState(States.FADE)) { + delay(100); + } + + print("Fade Achieved."); + } + } + + return true; + }; + + // Open a red portal. Mode 0 = mini ubers, mode 1 = Tristram + this.openPortal = function (mode) { + var portal, + item1 = mode === ItemModes.Item_In_Inventory_Stash_Cube_Or_Store ? me.findItem("pk1", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store) : me.findItem("dhn", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store), + item2 = mode === ItemModes.Item_In_Inventory_Stash_Cube_Or_Store ? me.findItem("pk2", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store) : me.findItem("bey", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store), + item3 = mode === ItemModes.Item_In_Inventory_Stash_Cube_Or_Store ? me.findItem("pk3", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store) : me.findItem("mbr", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); + + Town.goToTown(5); + Town.doChores(); + + if (Town.openStash() && Cubing.emptyCube()) { + if (!Storage.Cube.MoveTo(item1) || !Storage.Cube.MoveTo(item2) || !Storage.Cube.MoveTo(item3)) { + return false; + } + + if (!Cubing.openCube()) { + return false; + } + + transmute(); + delay(1000); + + portal = getUnit(UnitType.Object, "portal"); + + if (portal) { + do { + switch (mode) { + case ObjectModes.Neutral: + if ([UniqueObjectIds.Shrine3, UniqueObjectIds.Shrine4, UniqueObjectIds.Shrine5].indexOf(portal.objtype) > -1 && this.doneAreas.indexOf(portal.objtype) === -1) { + this.doneAreas.push(portal.objtype); + + return copyUnit(portal); + } + + break; + case ObjectModes.Operating: + if (portal.objtype === UniqueObjectIds.Shrine6) { + return copyUnit(portal); + } + + break; + } + } while (portal.getNext()); + } + } + + return false; + }; + + // Do mini ubers or Tristram based on area we're already in + this.pandemoniumRun = function () { + var i, findLoc, skillBackup; + + switch (me.area) { + case Areas.UberLevels.Matrons_Den: // Matron's Den + Precast.doPrecast(true); + Pather.moveToPreset(Areas.UberLevels.Matrons_Den, UnitType.Object, UniqueObjectIds.Sparklychest, 2, 2); + Attack.kill(UnitClassID.Lilith); + //Attack.clear(5); + Pickit.pickItems(); + Town.goToTown(); + + break; + case Areas.UberLevels.Fogotten_Sands: // Forgotten Sands + Precast.doPrecast(true); + + findLoc = [20196, 8694, 20308, 8588, 20187, 8639, 20100, 8550, 20103, 8688, 20144, 8709, 20263, 8811, 20247, 8665]; + + for (i = 0; i < findLoc.length; i += 2) { + Pather.moveTo(findLoc[i], findLoc[i + 1]); + delay(500); + + if (getUnit(UnitType.NPC, UnitClassID.Uber_Duriel)) { + break; + } + } + + Attack.kill(UnitClassID.Uber_Duriel); + Pickit.pickItems(); + Town.goToTown(); + + break; + case Areas.UberLevels.Furnace_of_Pain: // Furnace of Pain + Precast.doPrecast(true); + Pather.moveToPreset(Areas.UberLevels.Furnace_of_Pain, UnitType.Object, UniqueObjectIds.Sparklychest, 2, 2); + Attack.kill(UnitClassID.Uber_Izual); + Pickit.pickItems(); + Town.goToTown(); + + break; + case Areas.UberLevels.Tristram: // Tristram + Pather.moveTo(25068, 5078); + Precast.doPrecast(true); + + findLoc = [25040, 5101, 25040, 5166, 25122, 5170]; + + for (i = 0; i < findLoc.length; i += 2) { + Pather.moveTo(findLoc[i], findLoc[i + 1]); + } + + Skill.setSkill(Skills.Paladin.Salvation, 0); + this.lure(UnitClassID.Uber_Mephisto); + Pather.moveTo(25129, 5198); + Skill.setSkill(Skills.Paladin.Salvation, 0); + this.lure(UnitClassID.Uber_Mephisto); + + if (!getUnit(UnitType.NPC, UnitClassID.Uber_Mephisto)) { + Pather.moveTo(25122, 5170); + } + + if (Config.OrgTorch.UseSalvation && me.classid === ClassID.Paladin && me.getSkill(Skills.Paladin.Salvation, 1)) { + skillBackup = Config.AttackSkill[2]; + Config.AttackSkill[2] = Skills.Paladin.Salvation; + + Attack.init(); + } + + Attack.kill(UnitClassID.Uber_Mephisto); + + if (skillBackup && me.classid === ClassID.Paladin && me.getSkill(Skills.Paladin.Salvation, 1)) { + Config.AttackSkill[2] = skillBackup; + + Attack.init(); + } + + Pather.moveTo(25162, 5141); + delay(3250); + + if (!getUnit(UnitType.NPC, UnitClassID.Pandemonium_Diablo)) { + Pather.moveTo(25122, 5170); + } + + Attack.kill(UnitClassID.Pandemonium_Diablo); + + if (!getUnit(UnitType.NPC, UnitClassID.Uber_Baal)) { + Pather.moveTo(25122, 5170); + } + + Attack.kill(UnitClassID.Uber_Baal); + Pickit.pickItems(); + this.checkTorch(); + + break; + } + }; + + this.juvCheck = function () { + var i, + needJuvs = 0, + col = Town.checkColumns(Storage.BeltSize()); + + for (i = 0; i < 4; i += 1) { + if (Config.BeltColumn[i] === "rv") { + needJuvs += col[i]; + } + } + + print("Need " + needJuvs + " juvs."); + + return needJuvs; + }; + + // Start + var i, portal, tkeys, hkeys, dkeys, brains, eyes, horns, timer, farmer, busy, busyTick, + neededItems = {pk1: 0, pk2: 0, pk3: 0, rv: 0}; + + // Do town chores and quit if MakeTorch is true and we have a torch. + this.checkTorch(); + + // Wait for other bots to drop off their keys. This works only if TorchSystem.js is configured properly. + if (Config.OrgTorch.WaitForKeys) { + timer = getTickCount(); + + // Check if current character is the farmer + farmer = TorchSystem.isFarmer(); + + this.torchSystemEvent = function (mode, msg) { + var obj, farmer; + + if (mode === 6) { + farmer = TorchSystem.isFarmer(); + + if (farmer) { + obj = JSON.parse(msg); + + if (obj) { + switch (obj.name) { + case "gameCheck": + if (busy) { + break; + } + + if (farmer.KeyFinderProfiles.indexOf(obj.profile) > -1) { + print("Got game request from: " + obj.profile); + sendCopyData(null, obj.profile, 6, JSON.stringify({name: "gameName", value: {gameName: me.gamename, password: me.gamepassword}})); + + busy = true; + busyTick = getTickCount(); + } + + break; + case "keyCheck": + if (farmer.KeyFinderProfiles.indexOf(obj.profile) > -1) { + print("Got key count request from: " + obj.profile); + + // Get the number of needed keys + //neededItems = {pk1: 3 - tkeys, pk2: 3 - hkeys, pk3: 3 - dkeys, rv: this.juvCheck()}; + //print("Needed Keys: (" + (3 - tkeys).toString() + "," + (3 - hkeys).toString() + "," + (3 - dkeys).toString() + ")"); + + // Get the number of needed keys + neededItems = {pk1: (6 - tkeys), pk2: (6 - hkeys), pk3: (6 - dkeys), rv: this.juvCheck()}; + print("Needed Keys: (" + (6 - tkeys).toString() + "," + (6 - hkeys).toString() + "," + (6 - dkeys).toString() + ") Rejuv: " + this.juvCheck().toString()); + + sendCopyData(null, obj.profile, 6, JSON.stringify({name: "neededItems", value: neededItems})); + } + + break; + } + } + } + } + }; + + // Register event that will communicate with key hunters, go to Act 1 town and wait by stash + addEventListener('copydata', this.torchSystemEvent); + Town.goToTown(1); + Town.move("stash"); + + while (true) { + // Abort if the current character isn't a farmer + if (!farmer) { + break; + } + + // Free up inventory + if (Town.needStash()) { + Town.stash(); + } + + // Get the number keys + tkeys = me.findItems("pk1", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store).length || 0; + hkeys = me.findItems("pk2", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store).length || 0; + dkeys = me.findItems("pk3", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store).length || 0; + + // Stop the loop if we have enough keys or if wait time expired + if (((tkeys >= 3 && hkeys >= 3 && dkeys >= 3) || (Config.OrgTorch.WaitTimeout && (getTickCount() - timer > Config.OrgTorch.WaitTimeout * 1000 * 60))) && this.aloneInGame()) { + removeEventListener('copydata', this.torchSystemEvent); + + break; + } + + if (busy) { + while (getTickCount() - busyTick < 30000) { + if (!this.aloneInGame()) { + break; + } + + delay(100); + } + + if (getTickCount() - busyTick > 30000 || this.aloneInGame()) { + busy = false; + } + } + + // Wait for other characters to leave + while (!this.aloneInGame()) { + delay(500); + } + + delay(1000); + + // Pick the keys after the hunters drop them and leave the game + Pickit.pickItems(); + } + } + + // Count keys and organs + tkeys = me.findItems("pk1", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store).length || 0; + hkeys = me.findItems("pk2", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store).length || 0; + dkeys = me.findItems("pk3", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store).length || 0; + brains = me.findItems("mbr", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store).length || 0; + eyes = me.findItems("bey", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store).length || 0; + horns = me.findItems("dhn", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store).length || 0; + + // End the script if we don't have enough keys nor organs + if ((tkeys < 3 || hkeys < 3 || dkeys < 3) && (brains < 1 || eyes < 1 || horns < 1)) { + print("Not enough keys or organs."); + + return true; + } + + Config.UseMerc = false; + + // We have enough keys, do mini ubers + 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 + // If Config.OrgTorch.MakeTorch is false, check after at least one portal is made + if ((Config.OrgTorch.MakeTorch || i > 0) && this.completeSetCheck()) { + break; + } + + portal = this.openPortal(0); + + if (portal) { + Pather.usePortal(null, null, portal); + } + + this.pandemoniumRun(); + } + } + + // Don't make torches if not configured to OR if the char already has one + if (!Config.OrgTorch.MakeTorch || this.checkTorch()) { + return true; + } + + // Count organs + brains = me.findItems("mbr", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store).length || 0; + eyes = me.findItems("bey", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store).length || 0; + horns = me.findItems("dhn", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store).length || 0; + + // We have enough organs, do Tristram + if (brains && eyes && horns) { + this.getFade(); + print("Making torch"); + D2Bot.printToConsole("OrgTorch: Making torch.", 7); + + portal = this.openPortal(1); + + if (portal) { + Pather.usePortal(null, null, portal); + } + + this.pandemoniumRun(); + } + + return true; +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/OuterSteppes.js b/d2bs/kolbot/libs/bots/OuterSteppes.js new file mode 100644 index 000000000..1c29716eb --- /dev/null +++ b/d2bs/kolbot/libs/bots/OuterSteppes.js @@ -0,0 +1,13 @@ +function OuterSteppes() { + Town.goToTown(4); + Town.doChores(); + + if (!Pather.moveToExit(Areas.Act4.Outer_Steppes, true)) { + throw new Error("Failed to move to Outer Steppes"); + } + + Precast.doPrecast(true); + Attack.clearLevel(Config.ClearType); + + 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 6d89406a1..95eaed48f 100644 --- a/d2bs/kolbot/libs/bots/Pindleskin.js +++ b/d2bs/kolbot/libs/bots/Pindleskin.js @@ -5,34 +5,66 @@ */ function Pindleskin() { - Town.goToTown(5); + var anya; + + Town.goToTown(Config.Pindleskin.UseWaypoint ? undefined : 5); Town.doChores(); - Town.move("anya"); - if (!Pather.usePortal(121)) { - throw new Error("Failed to use portal."); + if (Config.Pindleskin.UseWaypoint) { + Pather.useWaypoint(Areas.Act5.Halls_Of_Pain); + Precast.doPrecast(true); + + if (!Pather.moveToExit([Areas.Act5.Halls_Of_Anguish, Areas.Act5.Nihlathaks_Temple], true)) { + throw new Error("Failed to move to Nihlahak's Temple"); + } + } else { + Town.move("anya"); + + if (!Pather.getPortal(Areas.Act5.Nihlathaks_Temple) && me.getQuest(Quests.Act5.Prison_of_Ice, 1)) { + anya = getUnit(UnitType.NPC, NPC.Anya); + + if (anya) { + anya.openMenu(); + me.cancel(); + } + } + + if (!Pather.usePortal(Areas.Act5.Nihlathaks_Temple)) { + throw new Error("Failed to use portal."); + } + + Precast.doPrecast(true); } - Precast.doPrecast(true); Pather.moveTo(10058, 13234); - Attack.clear(15, 0, getLocaleString(22497)); // Pindleskin + + try { + Attack.clear(15, 0, getLocaleString(22497)); // Pindleskin + } catch (e) { + print(e); + } if (Config.Pindleskin.KillNihlathak) { - if (!Pather.moveToExit([122, 123, 124], true)) { + if (!Pather.moveToExit([Areas.Act5.Halls_Of_Anguish, Areas.Act5.Halls_Of_Pain, Areas.Act5.Halls_Of_Vaught], true)) { throw new Error("Failed to move to Halls of Vaught"); } - Pather.moveToPreset(me.area, 2, 462, 0, 0, false, true); + Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Nihlathak_Outside_Town, 10, 10); - if (Config.Pindleskin.ViperQuit && getUnit(1, 597)) { + if (Config.Pindleskin.ViperQuit && getUnit(UnitType.NPC, UnitClassID.clawviper9)) { print("Tomb Vipers found."); return true; } + + if (Config.Pindleskin.ClearVipers) { + Attack.clearList(Attack.getMob(UnitClassID.clawviper9, 0, 20)); + } - Attack.kill(526); // Nihlathak - Attack.clear(20); + Attack.kill(UnitClassID.nihlathakboss); // Nihlathak + //Attack.clear(15, 0, 526); + Pickit.pickItems(); } return true; -} \ No newline at end of file +} diff --git a/d2bs/kolbot/libs/bots/Pit.js b/d2bs/kolbot/libs/bots/Pit.js index c686f9617..d5af4a55d 100644 --- a/d2bs/kolbot/libs/bots/Pit.js +++ b/d2bs/kolbot/libs/bots/Pit.js @@ -6,10 +6,10 @@ function Pit() { Town.doChores(); - Pather.useWaypoint(6); + Pather.useWaypoint(Areas.Act1.Black_Marsh); Precast.doPrecast(true); - if (!Pather.moveToExit([7, 12], true)) { + if (!Pather.moveToExit([Areas.Act1.Tamoe_Highland, Areas.Act1.Pit_Level_1], true)) { throw new Error("Failed to move to Pit level 1"); } @@ -17,7 +17,7 @@ function Pit() { Attack.clearLevel(Config.ClearType); } - if (!Pather.moveToExit(16, true, Config.Pit.ClearPath)) { + if (!Pather.moveToExit(Areas.Act1.Pit_Level_2, true, Config.Pit.ClearPath)) { throw new Error("Failed to move to Pit level 2"); } diff --git a/d2bs/kolbot/libs/bots/Questing.js b/d2bs/kolbot/libs/bots/Questing.js index c5f680b5c..102c4e3da 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 () { 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 () { var book, atma; if (!Town.goToTown() || !Pather.useWaypoint(48)) { 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 () { var tyrael; if (!Town.goToTown() || !Pather.useWaypoint(106)) { 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(); return true; }; this.lamEssen = function () { var stand, book, alkor; if (!Town.goToTown() || !Pather.useWaypoint(80)) { 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 (!Town.goToTown() || !Pather.useWaypoint(111)) { throw new Error(); } Precast.doPrecast(true); Pather.moveTo(3883, 5113); Attack.kill(getLocaleString(22435)); // Shenk the Overseer Town.goToTown(); return true; }; this.freeAnya = function () { var anya, malah, scroll; if (!Town.goToTown() || !Pather.useWaypoint(113)) { throw new Error(); } Precast.doPrecast(true); if (!Pather.moveToExit(114, true) || !Pather.moveToPreset(me.area, 2, 460)) { throw new Error(); } delay(1000); Attack.clear(10); 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(); scroll = me.getItem(646); clickItem(1, scroll); return true; }; for (i = 0; i < quests.length; i += 1) { if (!me.getQuest(quests[i][0], 0)) { try { this[quests[i][1]](); } catch (e) { print("Quest failed, moving to next one"); continue; } } } 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([Areas.Act1.Blood_Moor, Areas.Act1.Den_Of_Evil], true)) { throw new Error(); } Precast.doPrecast(true); Attack.clearLevel(); Town.goToTown(); Town.move("akara"); akara = getUnit(UnitType.NPC, "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(Areas.Act2.A2_Sewers_Level_2, true)) { throw new Error(); } Precast.doPrecast(true); if (!Pather.moveToExit(Areas.Act2.A2_Sewers_Level_3, true) || !Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Horadric_Scroll_Chest)) { throw new Error(); } Attack.kill(UnitClassID.radament); // Radament book = getUnit(UnitType.Item, ItemClassIds.Book_Of_Skill); if (book) { Pickit.pickItem(book); delay(300); clickItem(ClickType.Right_Click, book); } Town.goToTown(); Town.move("atma"); atma = getUnit(UnitType.NPC, "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(Areas.Act4.City_Of_The_Damned, true)) { throw new Error(); } Precast.doPrecast(true); if (!Pather.moveToPreset(Areas.Act4.Plains_Of_Despair, UnitType.NPC, UnitClassID.izual)) { return false; } Attack.kill(UnitClassID.izual); // Izual Town.goToTown(); Town.move("tyrael"); tyrael = getUnit(UnitType.NPC, "tyrael"); tyrael.openMenu(); me.cancel(); if (getUnit(UnitType.Object, UniqueObjectIds.Harrogath_LastPortal)) { Pather.useUnit(UnitType.Object, UniqueObjectIds.Harrogath_LastPortal, Areas.Act5.Harrogath); } return true; }; this.lamEssen = function () { if (!Pather.accessToAct(3)) { return false; } print("starting lam essen"); var stand, book, alkor; if (!Town.goToTown() || !Pather.useWaypoint(Areas.Act3.Kurast_Bazaar, true)) { throw new Error(); } Precast.doPrecast(true); if (!Pather.moveToExit(Areas.Act3.Ruined_Temple, true) || !Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Lam_Esens_Tome)) { throw new Error(); } stand = getUnit(UnitType.Object, UniqueObjectIds.Lam_Esens_Tome); Misc.openChest(stand); delay(300); book = getUnit(UnitType.Item, ItemClassIds.Lam_Esens_Tome); Pickit.pickItem(book); Town.goToTown(); Town.move("alkor"); alkor = getUnit(UnitType.NPC, "alkor"); alkor.openMenu(); me.cancel(); return true; }; this.killShenk = function () { if (!Pather.accessToAct(5)) { return false; } if (this.checkQuest(Quests.Act5.Seige_on_Haggorath, 1)) { return true; } print("starting shenk"); if (!Town.goToTown() || !Pather.useWaypoint(Areas.Act5.Frigid_Highlands, 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(Quests.Act5.Prison_of_Ice, 1)) { return true; } print("starting anya"); var anya, malah, scroll; if (!Town.goToTown() || !Pather.useWaypoint(Areas.Act5.Crystalized_Passage, true)) { throw new Error(); } Precast.doPrecast(true); if (!Pather.moveToExit(Areas.Act5.Frozen_River, true) || !Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Drehya_Outside_Town)) { throw new Error(); } delay(1000); anya = getUnit(UnitType.Object, UniqueObjectIds.Frozen_Anya); Pather.moveToUnit(anya); //anya.interact(); sendPacket(1, 0x13, 4, 0x2, 4, anya.gid); delay(300); me.cancel(); Town.goToTown(); Town.move("malah"); malah = getUnit(UnitType.NPC, "malah"); malah.openMenu(); me.cancel(); Town.move("portalspot"); Pather.usePortal(Areas.Act5.Frozen_River, me.name); anya.interact(); delay(300); me.cancel(); Town.goToTown(); Town.move("malah"); malah.openMenu(); me.cancel(); delay(500); scroll = me.getItem(ItemClassIds.Scroll_Of_Resistance); if (scroll) { clickItem(ClickType.Right_Click, 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/Radament.js b/d2bs/kolbot/libs/bots/Radament.js index 9b53c4269..fa051de0b 100644 --- a/d2bs/kolbot/libs/bots/Radament.js +++ b/d2bs/kolbot/libs/bots/Radament.js @@ -6,14 +6,14 @@ function Radament() { Town.doChores(); - Pather.useWaypoint(48); + Pather.useWaypoint(Areas.Act2.A2_Sewers_Level_2); Precast.doPrecast(true); - if (!Pather.moveToExit(49, true) || !Pather.moveToPreset(me.area, 2, 355)) { + if (!Pather.moveToExit(Areas.Act2.A2_Sewers_Level_3, true) || !Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Horadric_Scroll_Chest)) { throw new Error("Failed to move to Radament"); } - Attack.kill(229); // Radament + Attack.kill(UnitClassID.radament); // Radament Pickit.pickItems(); Attack.openChests(20); diff --git a/d2bs/kolbot/libs/bots/Rakanishu.js b/d2bs/kolbot/libs/bots/Rakanishu.js index f9e8e799c..d87dc2782 100644 --- a/d2bs/kolbot/libs/bots/Rakanishu.js +++ b/d2bs/kolbot/libs/bots/Rakanishu.js @@ -6,22 +6,22 @@ function Rakanishu() { Town.doChores(); - Pather.useWaypoint(4); + Pather.useWaypoint(Areas.Act1.Stony_Field); Precast.doPrecast(true); - if (!Pather.moveToPreset(me.area, 1, 737, 0, 0, false, true)) { + if (!Pather.moveToPreset(me.area, UnitType.NPC, SuperUniques.Rakanishu, 0, 0, false, true)) { throw new Error("Failed to move to Rakanishu"); } Attack.clear(15, 0, getLocaleString(2872)); // Rakanishu - if (Config.Rakanishu.KillGriswold && me.getQuest(4, 0)) { - if (!Pather.usePortal(38)) { + if (Config.Rakanishu.KillGriswold && me.getQuest(Quests.Act1.The_Search_for_Cain, 4)) { + if (!Pather.usePortal(Areas.Act1.Tristram)) { throw new Error("Failed to move to Tristram"); } Pather.moveTo(25149, 5180); - Attack.clear(20, 0xF, 365); // Griswold + Attack.clear(20, 0xF, UnitClassID.griswold); // Griswold } return true; diff --git a/d2bs/kolbot/libs/bots/Rushee.js b/d2bs/kolbot/libs/bots/Rushee.js index f1d67c470..615deca69 100644 --- a/d2bs/kolbot/libs/bots/Rushee.js +++ b/d2bs/kolbot/libs/bots/Rushee.js @@ -1,9 +1,12 @@ -// experimental script +/** +* @filename Rushee.js +* @author kolton +* @desc Rushee script that works with Rusher +*/ function Rushee() { - var quester, leader, target, - leaderName = "", - action = ""; + var act, leader, target, + actions = []; this.findLeader = function (name) { var party = getParty(name); @@ -15,10 +18,61 @@ function Rushee() { return false; }; + // Get leader's act from Party Unit + this.checkLeaderAct = function (unit) { + if (unit.area <= Areas.Act1.Moo_Moo_Farm) { + return 1; + } + + if (unit.area >= Areas.Act2.Lut_Gholein && unit.area <= Areas.Act2.Arcane_Sanctuary) {PlayerModes.Dead + return 2; + } + + if (unit.area >= Areas.Act3.Kurast_Docktown && unit.area <= Areas.Act3.Durance_Of_Hate_Level_3) { + return 3; + } + + if (unit.area >= Areas.Act4.The_Pandemonium_Fortress && unit.area <= Areas.Act4.Chaos_Sanctuary) { + return 4; + } + + return 5; + }; + + this.revive = function () { + while (me.mode === PlayerModes.Death) { + delay(40); + } + + if (me.mode === PlayerModes.Dead) { + me.revive(); + + while (!me.inTown) { + delay(40); + } + } + }; + + this.checkQuest = function (id, state) { + sendPacket(1, 0x40); + delay(500); + + return me.getQuest(id, state); + }; + this.getQuestItem = function (classid, chestid) { - var chest, item; + var chest, item, + tick = getTickCount(); + + if (me.getItem(classid)) { + return true; + } + + if (me.inTown) { + return false; + } - chest = getUnit(2, chestid); + chest = getUnit(UnitType.Object, chestid); if (!chest) { return false; @@ -26,20 +80,24 @@ function Rushee() { Misc.openChest(chest); - item = getUnit(4, classid); + item = getUnit(UnitType.Item, classid); if (!item) { + if (getTickCount() - tick < 500) { + delay(500); + } + return false; } - return Pickit.pickItem(item); + return Pickit.pickItem(item) && delay(1000); }; this.checkQuestMonster = function (classid) { - var monster = getUnit(1, classid); + var monster = getUnit(UnitType.NPC, classid); if (monster) { - while (monster.mode !== 12) { + while (monster.mode !== NPCModes.dead && monster.mode !== NPCModes.death) { delay(500); } @@ -57,21 +115,23 @@ function Rushee() { return false; } - for (i = 0; i < 5; i += 1) { + for (i = 0; i < 3; i += 1) { if (getDistance(me, npc) > 3) { Pather.moveToUnit(npc); } npc.interact(); - delay(500); + delay(1000 + me.ping); me.cancel(); - if (Pather.usePortal(null)) { - return true; + if (Pather.getPortal(null)) { + me.cancel(); + + break; } } - return false; + return Pather.usePortal(null) || Pather.usePortal(null, Config.Leader); }; this.cubeStaff = function () { @@ -85,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(); @@ -94,8 +155,9 @@ function Rushee() { }; this.placeStaff = function () { - var staff, - orifice = getUnit(2, 152); + var staff, item, + tick = getTickCount(), + orifice = getUnit(UnitType.Object, UniqueObjectIds.Holder_For_Horadric_Staff); if (!orifice) { return false; @@ -103,15 +165,26 @@ function Rushee() { Misc.openChest(orifice); - staff = me.getItem(91); + staff = me.getItem(ItemClassIds.Horadric_Staff); if (!staff) { + if (getTickCount() - tick < 500) { + delay(500); + } + return false; } staff.toCursor(); submitItem(); - delay(250 + me.ping); + delay(750 + me.ping); + + // unbug cursor + item = me.findItem(-1, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory); + + if (item && item.toCursor()) { + Storage.Inventory.MoveTo(item); + } return true; }; @@ -120,365 +193,770 @@ function Rushee() { var npc, preArea = me.area; - switch (act) { - case 2: - if (me.act >= 2) { - break; + if (me.mode === PlayerModes.Dead) { + me.revive(); + + while (!me.inTown) { + delay(500); } + } - Town.move("warriv"); + if (me.act === act) { + return true; + } - npc = getUnit(1, "warriv"); + try { + switch (act) { + case 2: + if (me.act >= 2) { + break; + } - if (!npc || !npc.openMenu()) { - return false; - } + Town.move("warriv"); - npc.useMenu(0x0D36); + npc = getUnit(UnitType.NPC, "warriv"); + + if (!npc || !npc.openMenu()) { + return false; + } + + Misc.useMenu(NPCMenu.Go_East); - break; - case 3: - if (me.act >= 3) { break; - } + case 3: + if (me.act >= 3) { + break; + } - Town.move("palace"); + Pather.usePortal(Areas.Act2.Harem_Level_1, Config.Leader); + Pather.moveToExit(Areas.Act2.Lut_Gholein, true); - npc = getUnit(1, "jerhyn"); + npc = getUnit(UnitType.NPC, "jerhyn"); - if (!npc || !npc.openMenu()) { - return false; - } + if (!npc || !npc.openMenu()) { + Pather.moveTo(5166, 5206); - me.cancel(); - Town.move("meshif"); + return false; + } - npc = getUnit(1, "meshif"); + me.cancel(); + Pather.moveToExit(Areas.Act2.Harem_Level_1, true); + Pather.usePortal(Areas.Act2.Lut_Gholein, Config.Leader); + Town.move("meshif"); - if (!npc || !npc.openMenu()) { - return false; - } + npc = getUnit(1, "meshif"); + + if (!npc || !npc.openMenu()) { + return false; + } - npc.useMenu(0x0D38); + Misc.useMenu(NPCMenu.Sail_East); - break; - case 4: - if (me.act >= 4) { break; - } + case 4: + if (me.act >= 4) { + break; + } - if (me.inTown) { - Town.move("cain"); + if (me.inTown) { + Town.move("cain"); - npc = getUnit(1, "deckard cain"); + npc = getUnit(UnitType.NPC, "deckard cain"); - if (!npc || !npc.openMenu()) { - return false; + if (!npc || !npc.openMenu()) { + return false; + } + + me.cancel(); + Pather.usePortal(Areas.Act3.Durance_Of_Hate_Level_3, Config.Leader); + } else { + delay(1500); } - me.cancel(); - Pather.usePortal(102, null); - } + Pather.moveTo(17591, 8070); + Pather.usePortal(null); - Pather.usePortal(null); - break; - case 5: - if (me.act >= 5) { break; - } + case 5: + if (me.act >= 5) { + break; + } - Town.move("tyrael"); + Town.move("tyrael"); - npc = getUnit(1, "tyrael"); + npc = getUnit(UnitType.NPC, "tyrael"); - if (!npc || !npc.openMenu()) { - return false; + if (!npc || !npc.openMenu()) { + return false; + } + + delay(me.ping + 1); + + if (getUnit(UnitType.Object, UniqueObjectIds.Harrogath_LastPortal)) { + me.cancel(); + Pather.useUnit(UnitType.Object, UniqueObjectIds.Harrogath_LastPortal, Areas.Act5.Harrogath); + } else { + Misc.useMenu(NPCMenu.Travel_to_Harrogath); + } + + break; } - me.cancel(); - Pather.usePortal(null); - break; - } + delay(1000 + me.ping * 2); - delay(2000 + me.ping); + while (!me.area) { + delay(500); + } - while (!me.area) { - delay(500); - } + if (me.area === preArea) { + me.cancel(); + Town.move("portalspot"); + say("Act change failed."); - if (me.area === preArea) { - me.cancel(); - Town.move("portalspot"); - say("Act change failed."); + return false; + } + say("Act change done."); + } catch (e) { return false; } - Town.move("portalspot"); - say("Act change done."); - return true; }; addEventListener("chatmsg", function (who, msg) { - if (who === leaderName) { - action = msg; + if (who === Config.Leader) { + actions.push(msg); } - } - ); + }); + + // START + if (me.inTown) { + Town.move("portalspot"); + } while (!leader) { - leader = this.findLeader(leaderName); - + leader = this.findLeader(Config.Leader); + delay(500); } say("Leader found."); - + while (true) { - switch (action) { - case "1": - while (!leader.area) { - delay(500); - } + try { + if (actions.length > 0) { + switch (actions[0]) { + case "all in": + switch (leader.area) { + case Areas.Act2.A2_Sewers_Level_3: // Pick Book of Skill, use Book of Skill + Town.move("portalspot"); + Pather.usePortal(Areas.Act2.A2_Sewers_Level_3, Config.Leader); + delay(500); - if (!quester) { - break; - } + while (true) { + target = getUnit(UnitType.Item, ItemClassIds.Book_Of_Skill); + + if (!target) { + break; + } + + Pickit.pickItem(target); + delay(250); - switch (leader.area) { - case 37: // Catacombs level 4 - Pather.usePortal(37, leaderName); - this.checkQuestMonster(156); + if (me.getItem(ItemClassIds.Book_Of_Skill)) { + print("Using book of skill"); + clickItem(ClickType.Right_Click, me.getItem(ItemClassIds.Book_Of_Skill)); - if (me.mode === 17) { - me.revive(); - - while (!me.inTown) { + break; + } + } + + Pather.usePortal(Areas.Act2.Lut_Gholein, Config.Leader); + actions.shift(); + + break; + } + + actions.shift(); + + break; + case "1": + while (!leader.area) { delay(500); } - } else { - Pather.usePortal(1, leaderName); - } - this.changeAct(2); + //print(leader.area); - action = ""; + if (!Config.Rushee.Quester) { + //print("not a quester"); + actions.shift(); - break; - case 60: // Halls of the Dead level 3 - Pather.usePortal(60, leaderName); - this.getQuestItem(549, 354); - Pather.usePortal(40, leaderName); + break; + } - action = ""; + act = this.checkLeaderAct(leader); - break; - case 61: // Claw Viper Temple level 2 - Pather.usePortal(61, leaderName); - this.getQuestItem(521, 149); - Pather.usePortal(40, leaderName); - Town.move("drognan"); + if (me.act !== act) { + Town.goToTown(act); + Town.move("portalspot"); + } - target = getUnit(1, "drognan"); + switch (leader.area) { + case Areas.Act1.Catacombs_Level_4: // Catacombs level 4 + if (!Pather.usePortal(Areas.Act1.Catacombs_Level_4, Config.Leader)) { + break; + } - if (target) { - target.openMenu(); - me.cancel(); - } + target = Pather.getPortal(null, Config.Leader); - Town.move("portalspot"); - say("drognan done"); + if (target) { + Pather.walkTo(target.x, target.y); + } - action = ""; + actions.shift(); - break; - case 64: // Maggot Lair level 3 - Pather.usePortal(64, leaderName); - this.getQuestItem(92, 356); - Pather.usePortal(40, leaderName); - this.cubeStaff(); + break; + case Areas.Act2.A2_Sewers_Level_3: + Town.move("portalspot"); - action = ""; + if (Pather.usePortal(Areas.Act2.A2_Sewers_Level_3, Config.Leader)) { + actions.shift(); + } - break; - case 74: // Arcane Sanctuary - Pather.usePortal(74, leaderName); - this.checkQuestMonster(250); - - if (me.mode === 17) { - me.revive(); - - while (!me.inTown) { + break; + case Areas.Act2.Halls_Of_The_Dead_Level_3: // Halls of the Dead level 3 + Pather.usePortal(Areas.Act2.Halls_Of_The_Dead_Level_3, Config.Leader); + this.getQuestItem(ItemClassIds.Horadric_Cube, ItemClassIds.Casque); + Pather.usePortal(Areas.Act2.Lut_Gholein, Config.Leader); + + actions.shift(); + + break; + case Areas.Act2.Claw_Viper_Temple_Level_2: // Claw Viper Temple level 2 + Pather.usePortal(Areas.Act2.Claw_Viper_Temple_Level_2, Config.Leader); + this.getQuestItem(ItemClassIds.Viper_Amulet, ItemClassIds.Lance); + Pather.usePortal(Areas.Act2.Lut_Gholein, Config.Leader); + Town.move("drognan"); + + target = getUnit(UnitType.NPC, "drognan"); + + if (target && target.openMenu()) { + actions.shift(); + me.cancel(); + say("drognan done"); + } + + Town.move("portalspot"); + + break; + case Areas.Act2.Maggot_Lair_Level_3: // Maggot Lair level 3 + Pather.usePortal(Areas.Act2.Maggot_Lair_Level_3, Config.Leader); + this.getQuestItem(ItemClassIds.Staff_of_Kings, ItemClassIds.Winged_Helm); delay(500); - } - } else { - Pather.usePortal(40, leaderName); - } + Pather.usePortal(Areas.Act2.Lut_Gholein, Config.Leader); + this.cubeStaff(); - Town.move("atma"); + actions.shift(); - target = getUnit(1, "atma"); + break; + case Areas.Act2.Arcane_Sanctuary: // Arcane Sanctuary + if (!Pather.usePortal(Areas.Act2.Arcane_Sanctuary, Config.Leader)) { + break; + } - if (target) { - target.openMenu(); - me.cancel(); - } + actions.shift(); + + break; + case Areas.Act2.Tal_Rashas_Tomb_1: // Tal Rasha's Tombs + case Areas.Act2.Tal_Rashas_Tomb_2: + case Areas.Act2.Tal_Rashas_Tomb_3: + case Areas.Act2.Tal_Rashas_Tomb_4: + case Areas.Act2.Tal_Rashas_Tomb_5: + case Areas.Act2.Tal_Rashas_Tomb_6: + case Areas.Act2.Tal_Rashas_Tomb_7: + Pather.usePortal(null, Config.Leader); + this.placeStaff(); + Pather.usePortal(Areas.Act2.Lut_Gholein, Config.Leader); + actions.shift(); + + break; + case Areas.Act2.Duriels_Lair: // Duriel's Lair + Pather.usePortal(Areas.Act2.Duriels_Lair, Config.Leader); + this.tyraelTalk(); + + actions.shift(); + + break; + case Areas.Act3.Travincal: // Travincal + if (!Pather.usePortal(Areas.Act3.Travincal, Config.Leader)) { + me.cancel(); + + break; + } - Town.move("portalspot"); + actions.shift(); - action = ""; + break; + case Areas.Act3.Ruined_Temple: // Ruined Temple + if (!Pather.usePortal(Areas.Act3.Ruined_Temple, Config.Leader)) { + me.cancel(); - break; - case 66: // Tal Rasha's Tombs - case 67: - case 68: - case 69: - case 70: - case 71: - case 72: - Pather.usePortal(null, leaderName); - this.placeStaff(); - Pather.usePortal(40, leaderName); - - action = ""; + break; + } - break; - case 73: // Duriel's Lair - Pather.usePortal(73, leaderName); - this.tyraelTalk(); - this.changeAct(3); + target = getUnit(UnitType.Object, UniqueObjectIds.Lam_Esens_Tome); - action = ""; + Misc.openChest(target); + delay(300); - break; - case 83: // Travincal - Pather.usePortal(83, leaderName); - this.checkQuestMonster(getLocaleString(2863)); - this.checkQuestMonster(getLocaleString(2862)); - this.checkQuestMonster(getLocaleString(2860)); - - if (me.mode === 17) { - me.revive(); - - while (!me.inTown) { + target = getUnit(UnitType.Item, ItemClassIds.Lam_Esens_Tome); + + Pickit.pickItem(target); + Pather.usePortal(Areas.Act3.Kurast_Docktown, Config.Leader); + Town.move("alkor"); + + target = getUnit(UnitType.NPC, "alkor"); + + if (target && target.openMenu()) { + me.cancel(); + } + + Town.move("portalspot"); + actions.shift(); + + break; + case Areas.Act3.Durance_Of_Hate_Level_3: // Durance of Hate level 3 + if (!Pather.usePortal(Areas.Act3.Durance_Of_Hate_Level_3, Config.Leader)) { + me.cancel(); + + break; + } + + actions.shift(); + + break; + case Areas.Act4.Outer_Steppes: // sometimes the portal can be in city of the damned... + case Areas.Act4.Plains_Of_Despair: + if (Pather.usePortal(null, Config.Leader)) { + actions.shift(); + } + + break; + case Areas.Act4.Chaos_Sanctuary: // Chaos Sanctuary + Pather.usePortal(Areas.Act4.Chaos_Sanctuary, Config.Leader); + Pather.moveTo(7762, 5268); + Packet.flash(me.gid); + delay(500); + Pather.walkTo(7763, 5267, 2); + + while (!getUnit(UnitType.NPC, UnitClassID.diablo)) { + delay(500); + } + + Pather.moveTo(7763, 5267); + actions.shift(); + + break; + case Areas.Act5.Bloody_Foothills: // Bloody Foothils + Pather.usePortal(Areas.Act5.Bloody_Foothills, Config.Leader); + actions.shift(); + + break; + case Areas.Act5.Frozen_River: // Frozen River + Town.move("malah"); + + target = getUnit(UnitType.NPC, "malah"); + + if (target && target.openMenu()) { + me.cancel(); + } + + Pather.usePortal(Areas.Act5.Frozen_River, Config.Leader); delay(500); + + target = getUnit(UnitType.Object, UniqueObjectIds.Frozen_Anya); + + if (target) { + Pather.moveToUnit(target); + sendPacket(1, 0x13, 4, 0x2, 4, target.gid); + delay(1000); + me.cancel(); + } + + actions.shift(); + + break; + default: // unsupported area + actions.shift(); + + break; } - } else { - Pather.usePortal(75, leaderName); - } - Town.move("cain"); + break; + case "2": // Go back to town and check quest + if (!Config.Rushee.Quester) { + switch (leader.area) { + // Non-questers can piggyback off quester out messages + case Areas.Act5.Bloody_Foothills: // Shenk + if (me.act === 5) { + Town.move("larzuk"); + + target = getUnit(UnitType.NPC, "larzuk"); + + if (target && target.openMenu()) { + me.cancel(); + } + } + + break; + case Areas.Act5.Frozen_River: // Anya + if (me.act === 5) { + Town.move("malah"); + + target = getUnit(UnitType.NPC, "malah"); + + if (target && target.openMenu()) { + me.cancel(); + } + + if (me.getItem(ItemClassIds.Scroll_Of_Resistance)) { + print("Using scroll of resistance"); + clickItem(ClickType.Right_Click, me.getItem(ItemClassIds.Scroll_Of_Resistance)); + } + } + + break; + case Areas.Act4.Outer_Steppes: + case Areas.Act4.Plains_Of_Despair: + if (me.act === 4 && this.checkQuest(Quests.Act4.The_Fallen_Angel, 1)) { + Town.move(NPC.Tyrael); + + target = getUnit(UnitType.NPC, "tyrael"); + + if (target && target.openMenu()) { + me.cancel(); + } + } + + break; + } - target = getUnit(1, "deckard cain"); + actions.shift(); - if (target) { - target.openMenu(); - me.cancel(); - } + break; + } - Town.move("portalspot"); + switch (me.area) { + case Areas.Act1.Catacombs_Level_4: // Catacombs level 4 + this.revive(); - action = ""; + // Go to town if not there, break if procedure fails + if (!me.inTown && !Pather.usePortal(1, Config.Leader)) { + break; + } - break; - case 102: // Durance of Hate level 3 - Pather.usePortal(102, leaderName); - this.checkQuestMonster(242); - - if (me.mode === 17) { - me.revive(); - - while (!me.inTown) { + if (!this.checkQuest(Quests.Act1.Sisters_to_the_Slaughter, 4)) { + D2Bot.printToConsole("Andariel quest failed", 9); + quit(); + } + + actions.shift(); + + break; + case Areas.Act2.A2_Sewers_Level_3: // Sewers 3 + this.revive(); + + if (!me.inTown && !Pather.usePortal(Areas.Act2.Lut_Gholein, Config.Leader)) { + break; + } + + actions.shift(); + + break; + case Areas.Act2.Arcane_Sanctuary: // Arcane Sanctuary + this.revive(); + + if (!me.inTown && !Pather.usePortal(Areas.Act2.Lut_Gholein, Config.Leader)) { + break; + } + + Town.move("atma"); + + target = getUnit(UnitType.NPC, UnitClassID.atma); // Atma + + if (target && target.openMenu()) { + me.cancel(); + } else { + break; + } + + if (!this.checkQuest(Quests.Act2.The_Summoner, 0)) { + D2Bot.printToConsole("Summoner quest failed", 9); + quit(); + } + + Town.move("portalspot"); + actions.shift(); + + break; + case Areas.Act3.Travincal: // Travincal + this.revive(); + + if (!me.inTown && !Pather.usePortal(Areas.Act3.Kurast_Docktown, Config.Leader)) { + break; + } + + Town.move("cain"); + + target = getUnit(UnitType.NPC, NPC.Cain); + + if (target && target.openMenu()) { + me.cancel(); + } else { + break; + } + + if (!this.checkQuest(Quests.Act3.The_Blackened_Temple, 0)) { + D2Bot.printToConsole("Travincal quest failed", 9); + quit(); + } + + Town.move("portalspot"); + actions.shift(); + + break; + case Areas.Act3.Durance_Of_Hate_Level_3: // Durance 2 + this.revive(); + + if (!Pather.usePortal(75, Config.Leader)) { + break; + } + + actions.shift(); + + break; + case Areas.Act4.Outer_Steppes: + case Areas.Act4.Plains_Of_Despair: + this.revive(); + + if (!me.inTown && !Pather.usePortal(Areas.Act4.The_Pandemonium_Fortress, Config.Leader)) { + break; + } + + if (this.checkQuest(Quests.Act4.The_Fallen_Angel, 1)) { + Town.move(NPC.Tyrael); + + target = getUnit(UnitType.NPC, "tyrael"); + + if (target && target.openMenu()) { + me.cancel(); + } + + Town.move("portalspot"); + } + + actions.shift(); + + break; + case Areas.Act4.Chaos_Sanctuary: // Chaos Sanctuary + this.revive(); + + if (me.gametype === GameType.Classic) { + D2Bot.restart(); + + break; + } + + if (!me.inTown && !Pather.usePortal(Areas.Act4.The_Pandemonium_Fortress, Config.Leader)) { + break; + } + + actions.shift(); + + break; + case Areas.Act5.Bloody_Foothills: // Bloody Foothils + this.revive(); + + if (!me.inTown && !Pather.usePortal(Areas.Act5.Harrogath, Config.Leader)) { + break; + } + + Town.move("larzuk"); + + target = getUnit(UnitType.NPC, "larzuk"); + + if (target && target.openMenu()) { + me.cancel(); + } + + Town.move("portalspot"); + actions.shift(); + + break; + case Areas.Act5.Frozen_River: // Frozen River + this.revive(); + + if (!me.inTown && !Pather.usePortal(Areas.Act5.Harrogath, Config.Leader)) { + break; + } + + Town.move("malah"); + + target = getUnit(UnitType.NPC, "malah"); + + if (target && target.openMenu()) { + me.cancel(); + } + + if (me.getItem(ItemClassIds.Scroll_Of_Resistance)) { + print("Using Scroll of Resistance"); + clickItem(ClickType.Right_Click, me.getItem(ItemClassIds.Scroll_Of_Resistance)); + } + + Town.move("portalspot"); + actions.shift(); + + break; + default: + Town.move("portalspot"); + actions.shift(); + + break; + } + + break; + case "3": // Bumper + if (!Config.Rushee.Bumper) { + actions.shift(); + + break; + } + + while (!leader.area) { delay(500); } - - Town.move("portalspot"); - Pather.usePortal(102, leaderName); - } - this.changeAct(4); + act = this.checkLeaderAct(leader); - action = ""; + if (me.act !== act) { + Town.goToTown(act); + Town.move("portalspot"); + } - break; - case 108: // Chaos Sanctuary - Pather.usePortal(108, leaderName); + switch (leader.area) { + case Areas.Act5.Arreat_Summit: // Arreat Summit + if (!Pather.usePortal(Areas.Act5.Arreat_Summit, Config.Leader)) { + break; + } - while (!getUnit(1, 243)) { - delay(500); - } + // Wait until portal is gone + while (Pather.getPortal(Areas.Act5.Harrogath, Config.Leader)) { + delay(500); + } - this.checkQuestMonster(243); - - if (me.gametype === 0) { - //quitGame(); - quit(); - } else { - if (me.mode === 17) { - me.revive(); - - while (!me.inTown) { + // Wait until portal is up again + while (!Pather.getPortal(Areas.Act5.Harrogath, Config.Leader)) { delay(500); } + + if (!Pather.usePortal(Areas.Act5.Harrogath, Config.Leader)) { + break; + } + + actions.shift(); + + break; + case Areas.Act5.The_Worldstone_Chamber: // Worldstone Chamber + if (!Pather.usePortal(Areas.Act5.The_Worldstone_Chamber, Config.Leader)) { + break; + } + + actions.shift(); + + break; } - - Pather.usePortal(103, leaderName); - this.changeAct(5); - } - action = ""; + break; + case "quit": + quit(); - break; - } + break; + case "exit": + case "bye ~": + D2Bot.restart(); - break; - case me.name + " quest": - say("I am quester."); - - quester = true; - action = ""; - - break; - case "quit": - quit(); - break; - case "exit": - quitGame(); - break; - case "a2": - if (!quester && me.act !== 2) { - this.changeAct(2); - } + break; + case "a2": + if (!this.changeAct(2)) { + break; + } - action = ""; + target = getUnit(UnitType.NPC, "jerhyn"); - break; - case "a3": - if (!quester && me.act !== 3) { - this.changeAct(3); - } + if (target) { + target.openMenu(); + } - action = ""; + me.cancel(); + Town.move("portalspot"); + actions.shift(); - break; - case "a4": - if (!quester && me.act !== 4) { - this.changeAct(4); - } + break; + case "a3": + if (!this.changeAct(3)) { + break; + } - action = ""; + Town.move("portalspot"); + actions.shift(); + + break; + case "a4": + if (!this.changeAct(4)) { + break; + } + + Town.move("portalspot"); + actions.shift(); + + break; + case "a5": + if (!this.changeAct(5)) { + break; + } + + Town.move("portalspot"); + actions.shift(); + + break; + case me.name + " quest": + say("I am quester."); - break; - case "a5": - if (!quester && me.act !== 5) { - this.changeAct(5); + Config.Rushee.Quester = true; + + actions.shift(); + + break; + default: // Invalid command + actions.shift(); + + break; + } } + } catch (e) { + if (me.mode === PlayerModes.Dead) { + me.revive(); - action = ""; + while (!me.inTown) { + delay(500); + } + } + } - break; + if (getUIFlag(UIFlags.Trade_Prompt_up_ok_cancel_player_or_in_Trade_w_player)) { + me.cancel(); } delay(500); diff --git a/d2bs/kolbot/libs/bots/Rusher.js b/d2bs/kolbot/libs/bots/Rusher.js index a81992028..1f18a5b9d 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 @@ -16,17 +16,76 @@ function Rusher() { load("tools/rushthread.js"); delay(500); - var rushThread, command, master, - commands = []; - + var i, rushThread, command, master, commandSplit0, + commands = [], + 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 () { - rushThread.stop(); - load("tools/rushthread.js"); + rushThread = getScript("tools/rushthread.js"); + + if (rushThread) { + rushThread.stop(); + } + delay(500); + load("tools/rushthread.js"); rushThread = getScript("tools/rushthread.js"); + + delay(500); + }; + + this.getPlayerCount = function () { + var count = 0, + party = getParty(); + + if (party) { + do { + count += 1; + } while (party.getNext()); + } + + return count; + }; + + this.getPartyAct = function () { + var party = getParty(), + minArea = 999; + + do { + if (party.name !== me.name) { + while (!party.area) { + me.overhead("Waiting for party area info"); + delay(500); + } + + if (party.area < minArea) { + minArea = party.area; + } + } + } while (party.getNext()); + + if (minArea <= Areas.Act1.Moo_Moo_Farm) { + return 1; + } + + if (minArea >= Areas.Act2.Lut_Gholein && minArea <= Areas.Act2.Arcane_Sanctuary) { + return 2; + } + + if (minArea >= Areas.Act3.Kurast_Docktown && minArea <= Areas.Act3.Durance_Of_Hate_Level_3) { + return 3; + } + + if (minArea >= Areas.Act4.The_Pandemonium_Fortress && minArea <= Areas.Act4.Chaos_Sanctuary) { + return 4; + } + + return 5; }; this.chatEvent = function (nick, msg) { @@ -55,17 +114,19 @@ 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 (nick === master) { - commands.push(msg); - } else { - say("I'm only accepting commands from my master."); + if (msg && msg.match(/^do \w|^clear \d|^pause$|^resume$/gi)) { + if (nick === master) { + commands.push(msg); + } else { + say("I'm only accepting commands from my master."); + } } break; @@ -74,6 +135,37 @@ function Rusher() { }; addEventListener("chatmsg", this.chatEvent); + + while (this.getPlayerCount() < Math.min(8, Config.Rusher.WaitPlayerCount)) { + me.overhead("Waiting for players to join"); + delay(500); + } + + // Skip to a higher act if all party members are there + switch (this.getPartyAct()) { + case 2: + say("Party is in act 2, starting from act 2"); + rushThread.send("skiptoact 2"); + + break; + case 3: + say("Party is in act 3, starting from act 3"); + rushThread.send("skiptoact 3"); + + break; + case 4: + say("Party is in act 4, starting from act 4"); + rushThread.send("skiptoact 4"); + + break; + case 5: + say("Party is in act 5, starting from act 5"); + rushThread.send("skiptoact 5"); + + break; + } + + delay(200); rushThread.send("go"); while (true) { @@ -83,20 +175,47 @@ function Rusher() { switch (command) { case "pause": if (rushThread.running) { + say("Pausing"); + rushThread.pause(); } break; case "resume": if (!rushThread.running) { + say("Resuming"); + rushThread.resume(); } break; default: - if (command.split(" ")[0] !== undefined && command.split(" ")[0] === "do") { - this.reloadThread(); - rushThread.send(command.split(" ")[1]); + commandSplit0 = command.split(" ")[0]; + + if (commandSplit0 === undefined) { + break; + } + + if (commandSplit0.toLowerCase() === "do") { + for (i = 0; i < sequence.length; i += 1) { + if (command.split(" ")[1] && sequence[i].match(command.split(" ")[1], "gi")) { + this.reloadThread(); + rushThread.send(command.split(" ")[1]); + + break; + } + } + + if (i === sequence.length) { + say("Invalid sequence"); + } + } else if (commandSplit0.toLowerCase() === "clear") { + if (!isNaN(parseInt(command.split(" ")[1], 10)) && parseInt(command.split(" ")[1], 10) > 0 && parseInt(command.split(" ")[1], 10) <= 132) { + this.reloadThread(); + rushThread.send(command); + } else { + say("Invalid area"); + } } break; @@ -107,4 +226,4 @@ function Rusher() { } return true; -} \ No newline at end of file +} diff --git a/d2bs/kolbot/libs/bots/SealLeader.js b/d2bs/kolbot/libs/bots/SealLeader.js new file mode 100644 index 000000000..2dc2ff23f --- /dev/null +++ b/d2bs/kolbot/libs/bots/SealLeader.js @@ -0,0 +1,279 @@ +function SealLeader() { + this.getLayout = function (seal, value) { + var sealPreset = getPresetUnit(Areas.Act4.Chaos_Sanctuary, UnitType.Object, 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(UniqueObjectIds.Diablo_Seal5, 5275); + this.seisLayout = this.getLayout(UniqueObjectIds.Diablo_Seal3, 7773); + this.infLayout = this.getLayout(UniqueObjectIds.Diablo_Seal1, 7893); + }; + + this.getBoss = function (name) { + var i, boss, + glow = getUnit(UnitType.Object, UniqueObjectIds.Vile_Dog_Afterglow); + + for (i = 0; i < 16; i += 1) { + boss = getUnit(UnitType.NPC, 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 ClassID.Amazon: + break; + case ClassID.Sorceress: + break; + case ClassID.Necromancer: + break; + case ClassID.Paladin: + target = getUnit(UnitType.NPC, 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 ClassID.Barbarian: + break; + case ClassID.Druid: + break; + case ClassID.Assassin: + break; + } + }; + + this.diabloPrep = function () { + var trapCheck, + tick = getTickCount(); + + while (getTickCount() - tick < 17500) { + if (getTickCount() - tick >= 8000) { + switch (me.classid) { + case ClassID.Sorceress: // Sorceress + if ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard, Skills.Sorceress.Frozen_Orb].indexOf(Config.AttackSkill[1]) > -1) { + if (me.getState(States.SKILLDELAY)) { + delay(500); + } else { + Skill.cast(Config.AttackSkill[1], 0, 7793, 5293); + } + + break; + } + + delay(500); + + break; + case ClassID.Paladin: // Paladin + Skill.setSkill(Config.AttackSkill[2]); + Skill.cast(Config.AttackSkill[1], 1); + + break; + case ClassID.Druid: // Druid + if (Config.AttackSkill[1] === Skills.Druid.Tornado) { + Skill.cast(Config.AttackSkill[1], 0, 7793, 5293); + + break; + } + + delay(500); + + break; + case ClassID.Assassin: // Assassin + if (Config.UseTraps) { + trapCheck = ClassAttack.checkTraps({x: 7793, y: 5293}); + + if (trapCheck) { + ClassAttack.placeTraps({ x: 7793, y: 5293, classid: UnitClassID.diablo}, trapCheck); + + break; + } + } + + delay(500); + + break; + default: + delay(500); + } + } else { + delay(500); + } + + if (getUnit(UnitType.NPC, UnitClassID.diablo)) { + 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(Areas.Act4.Chaos_Sanctuary, UnitType.Object, classid, classid === UniqueObjectIds.Diablo_Seal3 ? 5 : 2, classid === UniqueObjectIds.Diablo_Seal3 ? 5 : 0); + + if (i > 1) { + Attack.clear(10); + } + + for (j = 0; j < 3; j += 1) { + seal = getUnit(UnitType.Object, 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 === UniqueObjectIds.Diablo_Seal3 ? 1000 : 500); + + if (!seal.mode) { + if (classid === UniqueObjectIds.Diablo_Seal3 && 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(Areas.Act4.River_Of_Flame); + 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(UniqueObjectIds.Diablo_Seal4); + this.openSeal(UniqueObjectIds.Diablo_Seal5); + + 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(UniqueObjectIds.Diablo_Seal3); + + 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(UniqueObjectIds.Diablo_Seal1); + + if (this.infLayout === 2) { + Pather.moveTo(7928, 5295); + } + + if (!this.getBoss(getLocaleString(2853))) { + throw new Error("Failed to kill Infector"); + } + + this.openSeal(UniqueObjectIds.Diablo_Seal2); + say("out"); + Pather.moveTo(7763, 5267); + Pather.makePortal(); + Pather.moveTo(7788, 5292); + say("in"); + this.diabloPrep(); + Attack.kill(UnitClassID.diablo); // 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..357f2c38b --- /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(Areas.Act4.Chaos_Sanctuary, 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(Areas.Act4.The_Pandemonium_Fortress, Config.Leader); + } + + commands.shift(); + + break; + } + } + + while (me.mode === 40) { + delay(40); + } + + if (me.mode === PlayerModes.Dead) { + me.revive(); + + while (!me.inTown) { + delay(40); + } + } + + if (!me.inTown) { + monster = getUnit(UnitType.NPC); + + if (monster) { + do { + if (Attack.checkMonster(monster) && getDistance(me, monster) < 20) { + me.overhead("HOT"); + Pather.usePortal(Areas.Act4.The_Pandemonium_Fortress, Config.Leader); + } + } while (monster.getNext()); + } + } + + delay(100); + } + + return true; +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/SharpTooth.js b/d2bs/kolbot/libs/bots/SharpTooth.js new file mode 100644 index 000000000..cecc95833 --- /dev/null +++ b/d2bs/kolbot/libs/bots/SharpTooth.js @@ -0,0 +1 @@ +/** * @filename Sharptooth.js * @author loshmi * @desc kill Thresh Socket */ function SharpTooth() { Town.doChores(); Pather.useWaypoint(Areas.Act5.Frigid_Highlands); Precast.doPrecast(true); if (!Pather.moveToPreset(me.area, UnitType.NPC, SuperUniques.Sharp_Tooth_Sayer)) { throw new Error("Failed to move to Sharptooth Slayer"); } Attack.kill(getLocaleString(22493)); // Sharptooth Slayer Pickit.pickItems(); 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 34ac9bcf1..6359daa4e 100644 --- a/d2bs/kolbot/libs/bots/ShopBot.js +++ b/d2bs/kolbot/libs/bots/ShopBot.js @@ -1,19 +1,100 @@ function ShopBot() { - var npc, tickCount, town, wpArea, path, + var i, tickCount, cycles = 0, - cyclesText = new Text("Cycles in last minute: " + cycles, 50, 260, 2, 1), + cyclesText = new Text("Cycles in last minute:", 50, 260, 2, 1), + title = new Text("kolbot shopbot", 50, 245, 2, 1), + frequency = new Text("Valid item frequency:", 50, 275, 2, 1), + totalCyclesText = new Text("Total cycles:", 50, 290, 2, 1), + validItems = 0, leadRetry = 10, + totalCycles = 0, 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], path[i + 1]); + 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) { - if (getDistance(npc.x, npc.y, path[i], path[i + 1]) < 4) { + while (npc.mode === NPCModes.walk) { + delay(100); + } + + if (getDistance(me, npc) < (i === path.length - 2 ? 8 : 5)) { break; } @@ -34,129 +115,539 @@ function ShopBot() { return true; }; - this.shopItems = function () { - var i, items, - npc = getInteractedNPC(); + this.openMenu = function (npc) { + if (npc.type !== UnitType.NPC) { + 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(UIFlags.npc_menu)) { + return true; + } + + for (i = 0; i < 10; i += 1) { + if (getDistance(me.x, me.y, npc.x, npc.y) > 5) { + Pather.walkTo(npc.x, npc.y); + } + + if (!getUIFlag(UIFlags.npc_menu)) { + sendPacket(1, 0x13, 4, 1, 4, npc.gid); + sendPacket(1, 0x2f, 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(UIFlags.npc_menu)) { + //print("openMenu try: " + i); + + return true; + } + + delay(10); + } + } + + me.cancel(); + + return false; + }; + + this.shopItems = function (npc, menuId) { + var i, item, items, bought; + + if (!Storage.Inventory.CanFit({sizex: 2, sizey: 4}) && AutoMule.getMuleItems().length > 0) { + D2Bot.printToConsole("Mule triggered"); + scriptBroadcast("mule"); + scriptBroadcast("quit"); + + return true; + } if (!npc) { return false; } - items = npc.getItems(); + for (i = 0; i < 10; i += 1) { + delay(150); - if (!items || !items.length) { + if (i % 2 === 0) { + sendPacket(1, 0x38, 4, 1, 4, npc.gid, 4, 0); + } + + if (npc.itemcount > 0) { + //delay(200); + + break; + } + } + + item = npc.getItem(); + + if (!item) { return false; } + items = []; + + do { + 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 base items / cycle: " + ((validItems / totalCycles).toFixed(2).toString()); + for (i = 0; i < items.length; i += 1) { - if (Config.ShopBot.ScanIDs.indexOf(items[i].classid) > -1) { - //print("Scanning " + items[i].name); - - if (Pickit.checkItem(items[i]) === 1) { - try { - if (Storage.Inventory.CanFit(items[i]) && me.getStat(14) + me.getStat(15) >= items[i].getItemCost(0)) { - Misc.logItem("Shopped", items[i]); - items[i].buy(); - } - } catch (e) { - print(e); - } + 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; } - unit = getUnit(2, "Waypoint"); + unit = getUnit(UnitType.Object, "waypoint"); if (!unit) { return false; } - if (me.inTown) { + if (getUIFlag(UIFlags.npc_menu)) { + 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, unit) > 5) { - Pather.moveToUnit(unit); - } - - unit.interact(area); + for (i = 0; i < 10; i += 1) { + if (me.area === unit.area && getDistance(me, unit) > 5) { + Pather.walkTo(unit.x, unit.y); } - delay(100); + 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; + } - if (me.area === area) { - return true; + delay(10); } } return false; }; - Town.doChores(); + this.shopAtNPC = function (name) { + var i, path, npc, menuId, wp, temp; + + switch (name) { + case "akara": + case "charsi": + if (me.inTown) { + if (!Town.goToTown(1)) { + break; + } + } else { + if (!this.useWp(1)) { + break; + } + } + + npc = this.npcs[name] || getUnit(1, name); + + if (!npc) { + Town.move(name); + + npc = getUnit(UnitType.NPC, name); + } + + if (!npc) { + Town.move("waypoint"); + + npc = getUnit(UnitType.NPC, name); + } + + if (!npc) { + break; + } + + if (!this.npcs[name]) { + this.npcs[name] = copyUnit(npc); + } + + if (!this.paths[name]) { + if (!getUnit(UnitType.Object, "waypoint")) { + Town.move("waypoint"); + } + + wp = getUnit(UnitType.Object, "waypoint"); + wp = {x: wp.x, y: wp.y}; + + Town.move(name); + + path = getPath(me.area, npc.x, npc.y, wp.x + 2, wp.y + 2, 0, 8); + this.paths[name] = []; - switch (Config.ShopBot.ShopNPC.toLowerCase()) { - case "anya": - wpArea = 129; - town = 109; - path = [5122, 5119, 5129, 5105, 5123, 5087, 5115, 5068]; + for (i = 0; i < path.length; i += 1) { + temp = Pather.getNearestWalkable(path[i].x, path[i].y, 5, 1, 0x1 | 0x400, 4); - if (!Town.goToTown(5) || !Town.move(NPC.Anya)) { - throw new Error("Failed to get to NPC"); + 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); + } + } + } + + path = this.paths[name]; + menuId = "Shop"; + + break; + case "elzix": + if (me.inTown) { + if (!Town.goToTown(2)) { + break; + } + } else { + if (!this.useWp(Areas.Act2.Lut_Gholein)) { + break; + } + } + + npc = this.npcs[name] || getUnit(UnitType.NPC, NPC.Elzix); + + if (!npc) { + Town.move(NPC.Elzix); + + npc = getUnit(UnitType.NPC, NPC.Elzix); + } + + if (!npc) { + Town.move("waypoint"); + + npc = getUnit(UnitType.NPC, NPC.Elzix); + } + + if (!npc) { + break; + } + + if (!this.npcs[name]) { + this.npcs[name] = copyUnit(npc); + } + + 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(Areas.Act2.Lut_Gholein)) { + break; + } + } + + npc = this.npcs[name] || getUnit(UnitType.NPC, NPC.Fara); + + if (!npc) { + Town.move(NPC.Fara); + + npc = getUnit(UnitType.NPC, NPC.Fara); + } + + if (!npc) { + Town.move("waypoint"); + + npc = getUnit(UnitType.NPC, 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(Areas.Act2.Lut_Gholein)) { + break; + } + } + + npc = this.npcs[name] || getUnit(1, NPC.Drognan); + + if (!npc) { + Town.move(NPC.Drognan); + + npc = getUnit(UnitType.NPC, NPC.Drognan); + } + + if (!npc) { + Town.move("waypoint"); + + npc = getUnit(UnitType.NPC, 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(Areas.Act3.Kurast_Docktown)) { + break; + } + } + + npc = this.npcs[name] || getUnit(UnitType.NPC, NPC.Ormus); + + if (!npc) { + Town.move(NPC.Ormus); + + npc = getUnit(UnitType.NPC, NPC.Ormus); + } + + if (!npc) { + Town.move("waypoint"); + + npc = getUnit(UnitType.NPC, 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(Areas.Act3.Kurast_Docktown)) { + break; + } + } + + npc = this.npcs[name] || getUnit(UnitType.NPC, NPC.Asheara); + + if (!npc) { + Town.move(NPC.Asheara); + + npc = getUnit(UnitType.NPC, NPC.Asheara); + } + + if (!npc) { + Town.move("waypoint"); + + npc = getUnit(UnitType.NPC, 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(Areas.Act5.Harrogath)) { + break; + } + } + + npc = this.npcs[name] || getUnit(UnitType.NPC, NPC.Anya); + + if (!npc) { + Town.move(NPC.Anya); + + npc = getUnit(UnitType.NPC, NPC.Anya); + } + + if (!npc) { + Town.move("waypoint"); + + npc = getUnit(UnitType.NPC, 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"); + } + + if (npc) { + if (!this.mover(npc, path)) { + return false; + } + + if (Config.ShopBot.CycleDelay) { + delay(Config.ShopBot.CycleDelay); + } + + if (this.openMenu(npc)) { + this.shopItems(npc, menuId); + } } - npc = getUnit(1, NPC.Anya); + 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); + + i -= 1; + } + } + } - break; - default: - throw new Error("Invalid shopbot NPC."); + if (typeof Config.ShopBot.ShopNPC === "string") { + Config.ShopBot.ShopNPC = [Config.ShopBot.ShopNPC]; } - if (!npc) { - throw new Error("Failed to find NPC."); + for (i = 0; i < Config.ShopBot.ShopNPC.length; i += 1) { + Config.ShopBot.ShopNPC[i] = Config.ShopBot.ShopNPC[i].toLowerCase(); } - if (!this.mover(npc, path)) { - throw new Error("Failed to move NPC"); + if (Config.ShopBot.MinGold && me.getStat(Stats.gold) + me.getStat(Stats.goldbank) < Config.ShopBot.MinGold) { + return true; } - Town.move("waypoint"); + 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; - tickCount = getTickCount(); + cyclesText.text = "Cycles in last minute: " + cycles.toString(); + totalCyclesText.text = "Total cycles: " + totalCycles.toString(); cycles = 0; + tickCount = getTickCount(); } - if (me.area === town) { - npc.startTrade(); - this.shopItems(); - me.cancel(); - } - - if (me.area === town) { - 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([Areas.Act1.Catacombs_Level_2, Areas.Act2.A2_Sewers_Level_2, Areas.Act3.Durance_Of_Hate_Level_2, Areas.Act4.River_Of_Flame, Areas.Act5.Crystalized_Passage][me.act - 1]); } cycles += 1; + totalCycles += 1; } return true; diff --git a/d2bs/kolbot/libs/bots/Smith.js b/d2bs/kolbot/libs/bots/Smith.js index 09f704305..13178dbfd 100644 --- a/d2bs/kolbot/libs/bots/Smith.js +++ b/d2bs/kolbot/libs/bots/Smith.js @@ -6,10 +6,10 @@ function Smith() { Town.doChores(); - Pather.useWaypoint(27); + Pather.useWaypoint(Areas.Act1.Outer_Cloister); Precast.doPrecast(true); - if (!Pather.moveToPreset(28, 2, 108)) { + if (!Pather.moveToPreset(Areas.Act1.Barracks, UnitType.Object, UniqueObjectIds.Malus)) { throw new Error("Failed to move to the Smith"); } diff --git a/d2bs/kolbot/libs/bots/Snapchip.js b/d2bs/kolbot/libs/bots/Snapchip.js index 29a3e1763..201f73f87 100644 --- a/d2bs/kolbot/libs/bots/Snapchip.js +++ b/d2bs/kolbot/libs/bots/Snapchip.js @@ -6,10 +6,10 @@ function Snapchip() { Town.doChores(); - Pather.useWaypoint(118); + Pather.useWaypoint(Areas.Act5.Ancients_Way); Precast.doPrecast(true); - if (!Pather.moveToExit(119, true) || !Pather.moveToPreset(me.area, 2, 397)) { + if (!Pather.moveToExit(Areas.Act5.Icy_Cellar, true) || !Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Sparklychest)) { throw new Error("Failed to move to Snapchip Shatter"); } diff --git a/d2bs/kolbot/libs/bots/Stormtree.js b/d2bs/kolbot/libs/bots/Stormtree.js index 842983fb5..e19598641 100644 --- a/d2bs/kolbot/libs/bots/Stormtree.js +++ b/d2bs/kolbot/libs/bots/Stormtree.js @@ -1 +1 @@ -/** * @filename Stormtree.js * @author kolton * @desc kill Stormtree */ function Stormtree() { Town.doChores(); Pather.useWaypoint(79); Precast.doPrecast(true); if (!Pather.moveToExit(78, true)) { throw new Error("Failed to move to Stormtree"); } Attack.clear(15, 0, getLocaleString(2866)); // Stormtree return true; } \ No newline at end of file +/** * @filename Stormtree.js * @author kolton * @desc kill Stormtree */ function Stormtree() { Town.doChores(); Pather.useWaypoint(Areas.Act3.Lower_Kurast); Precast.doPrecast(true); if (!Pather.moveToExit(Areas.Act3.Flayer_Jungle, true)) { throw new Error("Failed to move to Stormtree"); } Attack.clear(15, 0, getLocaleString(2866)); // Stormtree return true; } \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/Summoner.js b/d2bs/kolbot/libs/bots/Summoner.js index c52ecfa12..3f4aed5d5 100644 --- a/d2bs/kolbot/libs/bots/Summoner.js +++ b/d2bs/kolbot/libs/bots/Summoner.js @@ -6,15 +6,26 @@ function Summoner() { Town.doChores(); - Pather.useWaypoint(74); + Pather.useWaypoint(Areas.Act2.Arcane_Sanctuary); Precast.doPrecast(true); - if (!Pather.moveToPreset(me.area, 2, 357)) { + if (Config.Summoner.FireEye) { + if (!Pather.usePortal(null)) { + throw new Error("Failed to move to Fire Eye"); + } + + Attack.clear(15, 0, getLocaleString(2885)); // Fire Eye + + if (!Pather.usePortal(null)) { + throw new Error("Failed to move to Summoner"); + } + } + + if (!Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Horazons_Journal, -3, -3)) { throw new Error("Failed to move to Summoner"); } - Attack.kill(250); // The Summoner - Pickit.pickItems(); + Attack.clear(15, 0, UnitClassID.summoner); // The Summoner return true; } \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/Synch.js b/d2bs/kolbot/libs/bots/Synch.js new file mode 100644 index 000000000..6cfdaba9b --- /dev/null +++ b/d2bs/kolbot/libs/bots/Synch.js @@ -0,0 +1,52 @@ +var Synched = false; + +var uRdyMsg = "I'm rdy, u?"; +var rdyMsg = "rdy"; + +function messageHandler(nick, msg) { + if (nick !== me.name) { + if (msg === uRdyMsg) { + say(rdyMsg); + Synched = true; + } else if (msg === rdyMsg) { + Synched = true; + } else if (msg === "Yo, I'm rdy, u?") { + say("No"); + quit(); + } + } +} + +function Synch() { + var i, party, j; + + addEventListener("chatmsg", messageHandler); + + delay(1000); + say(uRdyMsg); + + for (i = 0; i < 720 && !Synched; i += 1) { + delay(1000); + + for (j = 0; j < Config.Synch.WaitFor.length; j += 1) { + party = getParty(Config.Synch.WaitFor[j]); + if (!party) { + D2Bot.printToConsole("WaitFor not in game: " + + Config.Synch.WaitFor[j] + " so quitting."); + + removeEventListener("chatmsg", messageHandler); + quit(); + return false; + } + } + } + + if (!Synched) { + D2Bot.printToConsole("Failed to sync."); + quit(); + } + + removeEventListener("chatmsg", messageHandler); + + return true; +} diff --git a/d2bs/kolbot/libs/bots/Synch2.js b/d2bs/kolbot/libs/bots/Synch2.js new file mode 100644 index 000000000..5934ebb6f --- /dev/null +++ b/d2bs/kolbot/libs/bots/Synch2.js @@ -0,0 +1,56 @@ +var Synched2 = false; + +var uRdyMsg2 = "Yo, I'm rdy, u?"; +var rdyMsg2 = "Let's go"; + +function messageHandler2(nick, msg) { + if (nick !== me.name) { + if (msg === uRdyMsg2) { + say(rdyMsg2); + Synched2 = true; + } else if (msg === rdyMsg2) { + Synched2 = true; + } else if (msg === "I'm rdy, u?") { + say("No"); + quit(); + } + } +} + +function Synch2() { + var i, party, j; + + addEventListener("chatmsg", messageHandler2); + + delay(1000); + say(uRdyMsg2); + + delay(1000); + + for (i = 0; i < 720 && !Synched2; i += 1) { + for (j = 0; j < Config.Synch.WaitFor.length; j += 1) { + party = getParty(Config.Synch.WaitFor[j]); + if (!party) { + D2Bot.printToConsole("WaitFor not in game: " + + Config.Synch.WaitFor[j] + " so quitting."); + + removeEventListener("chatmsg", messageHandler2); + quit(); + return false; + } + } + + delay(1000); + } + + if (!Synched) { + D2Bot.printToConsole("Failed to sync."); + quit(); + } + + delay(1000); + + removeEventListener("chatmsg", messageHandler2); + + return true; +} diff --git a/d2bs/kolbot/libs/bots/Test.js b/d2bs/kolbot/libs/bots/Test.js index c263251ac..be9df2398 100644 --- a/d2bs/kolbot/libs/bots/Test.js +++ b/d2bs/kolbot/libs/bots/Test.js @@ -1,6 +1,6 @@ function Test() { print("ÿc8TESTING"); - + var c; function KeyDown(key) { @@ -8,13 +8,18 @@ function Test() { c = true; } } - + addEventListener("keydown", KeyDown); while (true) { if (c) { - test(); - + try { + test(); + } catch (qq) { + print('faile'); + print(qq + " " + qq.fileName + " " + qq.lineNumber); + } + c = false; } @@ -23,5 +28,7 @@ function Test() { } function test() { - Attack.clear(30); -} \ No newline at end of file + print("test"); + + print("done"); +} diff --git a/d2bs/kolbot/libs/bots/ThreshSocket.js b/d2bs/kolbot/libs/bots/ThreshSocket.js index 6e659a5a4..4b0b1433e 100644 --- a/d2bs/kolbot/libs/bots/ThreshSocket.js +++ b/d2bs/kolbot/libs/bots/ThreshSocket.js @@ -1 +1 @@ -/** * @filename ThreshSocket.js * @author kolton * @desc kill Thresh Socket */ function ThreshSocket() { Town.doChores(); Pather.useWaypoint(112); Precast.doPrecast(true); if (!Pather.moveToExit(113, false)) { throw new Error("Failed to move to Thresh Socket"); } Attack.kill(getLocaleString(22498)); // Thresh Socket Pickit.pickItems(); return true; } \ No newline at end of file +/** * @filename ThreshSocket.js * @author kolton * @desc kill Thresh Socket */ function ThreshSocket() { Town.doChores(); Pather.useWaypoint(Areas.Act5.Arreat_Plateau); Precast.doPrecast(true); if (!Pather.moveToExit(Areas.Act5.Crystalized_Passage, false)) { throw new Error("Failed to move to Thresh Socket"); } Attack.kill(getLocaleString(22498)); // Thresh Socket Pickit.pickItems(); return true; } \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/Tombs.js b/d2bs/kolbot/libs/bots/Tombs.js index 94ce3e0c3..887cf25ec 100644 --- a/d2bs/kolbot/libs/bots/Tombs.js +++ b/d2bs/kolbot/libs/bots/Tombs.js @@ -8,21 +8,21 @@ function Tombs() { var i; Town.doChores(); - Pather.useWaypoint(46); + Pather.useWaypoint(Areas.Act2.Canyon_Of_The_Magi); Precast.doPrecast(true); - for (i = 66; i <= 72; i += 1) { + for (i = Areas.Act2.Tal_Rashas_Tomb_1; i <= Areas.Act2.Tal_Rashas_Tomb_7; i += 1) { if (!Pather.moveToExit(i, true)) { throw new Error("Failed to move to tomb"); } Attack.clearLevel(Config.ClearType); - if (i === 69) { + if (i === Areas.Act2.Tal_Rashas_Tomb_4) { Precast.doPrecast(true); } - if (!Pather.moveToExit(46, true)) { + if (!Pather.moveToExit(Areas.Act2.Canyon_Of_The_Magi, true)) { throw new Error("Failed to move to Canyon"); } } diff --git a/d2bs/kolbot/libs/bots/Travincal.js b/d2bs/kolbot/libs/bots/Travincal.js index ced3609c5..c2bc61f5a 100644 --- a/d2bs/kolbot/libs/bots/Travincal.js +++ b/d2bs/kolbot/libs/bots/Travincal.js @@ -1 +1 @@ -/** * @filename Travincal.js * @author kolton * @desc kill Counncil members in Travincal */ function Travincal() { var i, orgX, orgY; this.buildList = function () { var monsterList = [], monster = getUnit(1); if (monster) { do { if ([345, 346, 347].indexOf(monster.classid) > -1 && Attack.checkMonster(monster)) { monsterList.push(copyUnit(monster)); } } while (monster.getNext()); } return monsterList; } Town.doChores(); Pather.useWaypoint(83); Precast.doPrecast(true); orgX = me.x; orgY = me.y; Pather.moveTo(orgX + 101, orgY - 56); if (me.classid === 4 && !me.getSkill(54, 1) && me.gametype === 1) { Pather.moveToExit([100, 83], true); } Attack.clearList(this.buildList()); return true; } \ No newline at end of file +/** * @filename Travincal.js * @author kolton * @desc kill Counncil members in Travincal */ function Travincal() { var i, orgX, orgY, coords; this.buildList = function (checkColl) { var monsterList = [], monster = getUnit(UnitType.NPC); if (monster) { do { if ([UnitClassID.councilmember1, UnitClassID.councilmember2, UnitClassID.councilmember3].indexOf(monster.classid) > -1 && Attack.checkMonster(monster) && (!checkColl || !checkCollision(me, monster, 0x1))) { monsterList.push(copyUnit(monster)); } } while (monster.getNext()); } return monsterList; }; Town.doChores(); Pather.useWaypoint(Areas.Act3.Travincal); Precast.doPrecast(true); orgX = me.x; orgY = me.y; if (Config.Travincal.PortalLeech) { Pather.moveTo(orgX + 85, orgY - 139); Attack.securePosition(orgX + 70, orgY - 139, 25, 2000); Attack.securePosition(orgX + 100, orgY - 139, 25, 2000); Attack.securePosition(orgX + 85, orgY - 139, 25, 5000); Pather.moveTo(orgX + 85, orgY - 139); Pather.makePortal(); delay(1000); Precast.doPrecast(true); } if (me.getSkill(Skills.Barbarian.Leap_Attack, 0) && !me.getSkill(Skills.Sorceress.Teleport, 0) && !me.getStat(Stats.item_nonclassskill, Skills.Sorceress.Teleport)) { coords = [60, -53, 64, -72, 78, -72, 74, -88]; for (i = 0; i < coords.length; i += 2) { if (i % 4 === 0) { Pather.moveTo(orgX + coords[i], orgY + coords[i + 1]); } else { Skill.cast(Skills.Barbarian.Leap_Attack, 0, orgX + coords[i], orgY + coords[i + 1]); Attack.clearList(this.buildList(1)); } } Attack.clearList(this.buildList(0)); } else { Pather.moveTo(orgX + 101, orgY - 56); // Stack Merc if (me.classid === ClassID.Barbarian && !me.getSkill(Skills.Sorceress.Teleport, 1) && me.gametype === GameType.Expansion) { Pather.moveToExit([Areas.Act3.Durance_Of_Hate_Level_1, Areas.Act3.Travincal], true); } if (Config.MFLeader) { Pather.makePortal(); say("council " + me.area); } Attack.clearList(this.buildList(0)); } return true; } \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/TravincalLeech.js b/d2bs/kolbot/libs/bots/TravincalLeech.js new file mode 100644 index 000000000..bc4aa813d --- /dev/null +++ b/d2bs/kolbot/libs/bots/TravincalLeech.js @@ -0,0 +1,35 @@ +/** +* @filename TravincalLeech.js +* @author ToS/XxXGoD/YGM +* @desc Travinical Leech +*/ + +function TravincalLeech() { + Town.goToTown(3); + Town.move("portalspot"); + + while (!Misc.inMyParty(Config.Leader)) { + delay(500); + } + + while (Misc.inMyParty(Config.Leader)) { + if (me.inTown && Pather.getPortal(Areas.Act3.Travincal, Config.Leader)) { + Pather.usePortal(Areas.Act3.Travincal, Config.Leader); + Town.getCorpse(); + } + + if (me.mode === PlayerModes.Dead) { + me.revive(); + + while (!me.inTown) { + delay(100); + } + + Town.move("portalspot"); + } + + delay(100); + } + + return true; +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/Treehead.js b/d2bs/kolbot/libs/bots/Treehead.js index 631df6126..63e062f25 100644 --- a/d2bs/kolbot/libs/bots/Treehead.js +++ b/d2bs/kolbot/libs/bots/Treehead.js @@ -6,10 +6,10 @@ function Treehead() { Town.doChores(); - Pather.useWaypoint(5); + Pather.useWaypoint(Areas.Act1.Dark_Wood); Precast.doPrecast(true); - if (!Pather.moveToPreset(me.area, 2, 30, 5, 5)) { + if (!Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Inifuss_Tree, 5, 5)) { throw new Error("Failed to move to Treehead"); } diff --git a/d2bs/kolbot/libs/bots/Tristram.js b/d2bs/kolbot/libs/bots/Tristram.js index f2cead3aa..b431abc52 100644 --- a/d2bs/kolbot/libs/bots/Tristram.js +++ b/d2bs/kolbot/libs/bots/Tristram.js @@ -1,35 +1,92 @@ /** * @filename Tristram.js -* @author kolton +* @author kolton, cuss * @desc clear Tristram */ function Tristram() { - if (!me.getQuest(4, 0)) { - throw new Error("You don't have the Cain quest"); - } + var tree, scroll, akara, stones, gibbet; + + if (!me.getQuest(Quests.Act1.The_Search_for_Cain, 4) && !me.getItem(ItemClassIds.Key_To_The_Cairn_Stones)) { + if (!me.getItem(ItemClassIds.Scroll_Of_Inifuss)) { + // print("We need Scroll of Inifuss"); + Town.doChores(); + Pather.useWaypoint(Areas.Act1.Dark_Wood); + Precast.doPrecast(true); + + if (!Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Inifuss_Tree, 5, 5)) { + throw new Error("Failed to move to Tree of Inifuss"); + } + + tree = getUnit(UnitType.Object, UniqueObjectIds.Inifuss_Tree); + + Misc.openChest(tree); + delay(300); + + scroll = getUnit(UnitType.Item, ItemClassIds.Scroll_Of_Inifuss); - var i; + Pickit.pickItem(scroll); + Town.goToTown(); + } + + // print("We need Key to the Cairn Stones"); + Town.move("akara"); + + akara = getUnit(UnitType.NPC, "akara"); + + akara.openMenu(); + me.cancel(); + } Town.doChores(); - Pather.useWaypoint(4); + Pather.useWaypoint(Areas.Act1.Stony_Field); Precast.doPrecast(true); - if (!Pather.moveToPreset(me.area, 1, 737, 0, 0, false, true)) { + if (!Pather.moveToPreset(me.area, UnitType.NPC, SuperUniques.Rakanishu, 0, 0, false, true)) { throw new Error("Failed to move to Rakanishu"); } + if (!me.getQuest(Quests.Act1.The_Search_for_Cain, 4)) { + stones = [getUnit(UnitType.Object, UniqueObjectIds.StoneAlpha), getUnit(UnitType.Object, UniqueObjectIds.StoneBeta), getUnit(UnitType.Object, UniqueObjectIds.StoneGamma), getUnit(UnitType.Object, UniqueObjectIds.StoneDelta), getUnit(UnitType.Object, UniqueObjectIds.StoneLambda)]; + } + Attack.clear(15, 0, getLocaleString(2872)); // Rakanishu - for (i = 0; i < 5; i += 1) { - if (Pather.usePortal(38)) { - break; - } + while (!me.getQuest(Quests.Act1.The_Search_for_Cain, 4)) { + stones.forEach(function (stone) { + if (!stone.mode) { + Attack.securePosition(stone.x, stone.y, 10, me.ping * 2); + Misc.click(0, 0, stone); + } + }); + } + + while (!Pather.usePortal(Areas.Act1.Tristram)) { + Attack.securePosition(me.x, me.y, 10, 1000); + } + + Pather.moveTo(me.x, me.y + 6); + if (Config.Tristram.PortalLeech) { + Pather.makePortal(); delay(1000); } - Attack.clearLevel(Config.ClearType); + gibbet = getUnit(UnitType.Object, UniqueObjectIds.Cain_Captured); + + if (!gibbet.mode) { + if (!Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Cain_Captured, 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); + } return true; } \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/TristramLeech.js b/d2bs/kolbot/libs/bots/TristramLeech.js new file mode 100644 index 000000000..6035e31b7 --- /dev/null +++ b/d2bs/kolbot/libs/bots/TristramLeech.js @@ -0,0 +1,109 @@ +/** +* @filename TristramLeech.js +* @author ToS/XxXGoD/YGM +* @desc Tristram Leech (Helper) +*/ + +function TristramLeech() { + + var leader, i; + + // Get leader's Unit + this.getLeaderUnit = function (name) { + var player = getUnit(UnitType.Player, name); + + if (player) { + do { + if (player.mode !== PlayerModes.Death && player.mode !== PlayerModes.Dead) { + return player; + } + } while (player.getNext()); + } + + return false; + }; + + Town.doChores(); + Pather.useWaypoint(Areas.Act1.Rogue_Encampment); // Back To Rouge + Town.move("portalspot"); // Portal Spot + + leader = Config.Leader; + + // Check leader isn't in other zones, whilst waiting for portal. + for (i = 0; i < Config.TristramLeech.Wait; i += 1) { + + var whereisleader = getParty(leader); + + if (whereisleader) { + if (whereisleader.area === Areas.Act3.Travincal) { + return false; + } + if (whereisleader.area === Areas.Act4.Chaos_Sanctuary) { + return false; + } + if (whereisleader.area === Areas.Act5.Throne_Of_Destruction) { + return false; + } + } + + if (Pather.usePortal(Areas.Act1.Tristram, leader)) { + break; + } + + delay(1000); + } + + if (i === Config.TristramLeech.Wait) { + throw new Error("No portal found to Tristram."); + } + + Precast.doPrecast(true); + delay(3000); + + for (i = 0; i < 30; i += 1) { + + var whereisleader = getParty(leader); + + if (whereisleader) { + if (whereisleader.area === Areas.Act1.Tristram) { + break; + } + } + + delay(1000); + } + + while (whereisleader.area === Areas.Act1.Tristram) { + + var whereisleader = getParty(leader); + var leaderUnit = this.getLeaderUnit(leader); + + if (whereisleader.area === me.area){ + try{ + if (copyUnit(leaderUnit).x) { + if (getDistance(me, leaderUnit) > 4) { + Pather.moveToUnit(leaderUnit); + Attack.clear(10); + } + } else { + Pather.moveTo(copyUnit(leaderUnit).x, copyUnit(leaderUnit).y); + Attack.clear(10); + } + } + catch(err){ + if (whereisleader.area === me.area){ + Pather.moveTo(whereisleader.x, whereisleader.y); + Attack.clear(10); + } + } + } + + delay(100); + } + + //if (partyleader.area === 38) { + // Attack.clearLevel(0); + //} + + return true; +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/UndergroundPassage.js b/d2bs/kolbot/libs/bots/UndergroundPassage.js new file mode 100644 index 000000000..b55f286f9 --- /dev/null +++ b/d2bs/kolbot/libs/bots/UndergroundPassage.js @@ -0,0 +1,19 @@ +/** +* @filename UndergroundPassage.js +* @author loshmi +* @desc Move and clear Underground passage level 2 +*/ + +function UndergroundPassage() { + Town.doChores(); + Pather.useWaypoint(Areas.Act1.Stony_Field); + Precast.doPrecast(true); + + if (!Pather.moveToExit([Areas.Act1.Underground_Passage_Level_1, Areas.Act1.Underground_Passage_Level_2], true)) { + throw new Error("Failed to move to Underground passage level 2"); + } + + Attack.clearLevel(); + + return true; +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/UserAddon.js b/d2bs/kolbot/libs/bots/UserAddon.js index f9ac0e80c..2ed638452 100644 --- a/d2bs/kolbot/libs/bots/UserAddon.js +++ b/d2bs/kolbot/libs/bots/UserAddon.js @@ -8,10 +8,10 @@ */ function UserAddon() { - var i, unit, + var i, unit, title, dummy, + info = new UnitInfo(), classes = ["Amazon", "Sorceress", "Necromancer", "Paladin", "Barbarian", "Druid", "Assassin"], - flags = [0x1, 0x2, 0x3, 0x4, 0x5, 0xf, 0x18, 0x19, 0xc, 0x9], - title = new Text(":: kolbot user addon ::", 400, 525, 4, 13, 2); + flags = [0x1, 0x2, 0x3, 0x4, 0x5, 0xf, 0x18, 0x19, 0xc, 0x9]; this.keyEvent = function (key) { switch (key) { @@ -38,26 +38,33 @@ function UserAddon() { while (true) { for (i = 0; i < flags.length; i += 1) { if (getUIFlag(flags[i])) { - title.visible = false; + if (title) { + title.remove(); + dummy.remove(); + + title = false; + dummy = false; + } break; } } - if (!title.visible && i === flags.length) { - title.visible = true; + if (i === flags.length && !title) { + title = new Text(":: kolbot user addon ::", 400, 525, 4, 0, 2); + dummy = new Text("`", 1, 1); // Prevents crash } Pickit.fastPick(); - unit = getUnit(101); + unit = getUnit(UnitType.Selected_Unit); - UnitInfo.createInfo(unit); - delay(10); + info.createInfo(unit); + delay(20); } } -var UnitInfo = new function () { +function UnitInfo() { this.x = 200; this.y = 250; this.hooks = []; @@ -71,17 +78,14 @@ var UnitInfo = new function () { } switch (unit.type) { - case 0: + case UnitType.Player: this.playerInfo(unit); - break; - case 1: + case UnitType.NPC: this.monsterInfo(unit); - break; - case 4: + case UnitType.Item: this.itemInfo(unit); - break; } }; @@ -107,7 +111,7 @@ var UnitInfo = new function () { this.hooks.push(new Text("Classid: ÿc0" + unit.classid, this.x, this.y, 4, 13, 2)); - items = unit.getItems(-1, 1); + items = unit.getItems(); if (items) { this.hooks.push(new Text("Equipped items:", this.x, this.y + 15, 4, 13, 2)); @@ -117,7 +121,7 @@ var UnitInfo = new function () { if (items[i].getFlag(0x4000000)) { string = items[i].fname.split("\n")[1] + "ÿc0 " + items[i].fname.split("\n")[0]; } else { - string = quality[items[i].quality] + (items[i].quality > 4 && items[i].getFlag(0x10) ? items[i].fname.split("\n")[1].replace("ÿc4", "") : items[i].name); + string = quality[items[i].quality] + (items[i].quality > 4 && items[i].getFlag(ItemFlags.isIdentified) ? items[i].fname.split("\n").reverse()[0].replace("ÿc4", "") : items[i].name); } this.hooks.push(new Text(string, this.x, this.y + (i + 2) * 15, 0, 13, 2)); @@ -156,12 +160,12 @@ var UnitInfo = new function () { this.hooks.push(new Text("Classid: ÿc0" + unit.classid, this.x, this.y, 4, 13, 2)); this.hooks.push(new Text("HP percent: ÿc0" + Math.round(unit.hp * 100 / 128), this.x, this.y + 15, 4, 13, 2)); - this.hooks.push(new Text("Fire resist: ÿc0" + unit.getStat(39), this.x, this.y + 30, 4, 13, 2)); - this.hooks.push(new Text("Cold resist: ÿc0" + unit.getStat(43), this.x, this.y + 45, 4, 13, 2)); - this.hooks.push(new Text("Lightning resist: ÿc0" + unit.getStat(41), this.x, this.y + 60, 4, 13, 2)); - this.hooks.push(new Text("Poison resist: ÿc0" + unit.getStat(45), this.x, this.y + 75, 4, 13, 2)); - this.hooks.push(new Text("Physical resist: ÿc0" + unit.getStat(36), this.x, this.y + 90, 4, 13, 2)); - this.hooks.push(new Text("Magic resist: ÿc0" + unit.getStat(37), this.x, this.y + 105, 4, 13, 2)); + this.hooks.push(new Text("Fire resist: ÿc0" + unit.getStat(Stats.fireresist), this.x, this.y + 30, 4, 13, 2)); + this.hooks.push(new Text("Cold resist: ÿc0" + unit.getStat(Stats.coldresist), this.x, this.y + 45, 4, 13, 2)); + this.hooks.push(new Text("Lightning resist: ÿc0" + unit.getStat(Stats.lightresist), this.x, this.y + 60, 4, 13, 2)); + this.hooks.push(new Text("Poison resist: ÿc0" + unit.getStat(Stats.poisonresist), this.x, this.y + 75, 4, 13, 2)); + this.hooks.push(new Text("Physical resist: ÿc0" + unit.getStat(Stats.damageresist), this.x, this.y + 90, 4, 13, 2)); + this.hooks.push(new Text("Magic resist: ÿc0" + unit.getStat(Stats.magicresist), this.x, this.y + 105, 4, 13, 2)); this.cleared = false; @@ -206,7 +210,7 @@ var UnitInfo = new function () { } } - if (unit.quality === 4 && unit.getFlag(0x10)) { + if (unit.quality === ItemQuality.Magic && unit.getFlag(ItemFlags.isIdentified)) { this.hooks.push(new Text("Prefix: ÿc0" + unit.prefixnum, this.x, this.y + frameYsize - 5, 4, 13, 2)); this.hooks.push(new Text("Suffix: ÿc0" + unit.suffixnum, this.x, this.y + frameYsize + 10, 4, 13, 2)); @@ -226,4 +230,4 @@ var UnitInfo = new function () { this.cleared = true; }; -}; \ No newline at end of file +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/Vizier.js b/d2bs/kolbot/libs/bots/Vizier.js index 584cddd3b..3ad525aed 100644 --- a/d2bs/kolbot/libs/bots/Vizier.js +++ b/d2bs/kolbot/libs/bots/Vizier.js @@ -8,7 +8,7 @@ function Vizier() { var i, tick, seal; this.openSeal = function (id) { - Pather.moveToPreset(108, 2, id, 4); + Pather.moveToPreset(Areas.Act4.Chaos_Sanctuary, UnitType.Object, id, 4); seal = getUnit(2, id); @@ -32,14 +32,14 @@ function Vizier() { }; Town.doChores(); - Pather.useWaypoint(107); + Pather.useWaypoint(Areas.Act4.River_Of_Flame); Precast.doPrecast(true); - if (!this.openSeal(396) || !this.openSeal(395)) { + if (!this.openSeal(UniqueObjectIds.Diablo_Seal5) || !this.openSeal(UniqueObjectIds.Diablo_Seal4)) { throw new Error("Failed to open seals"); } - Pather.moveToPreset(108, 2, 396, 4); + Pather.moveToPreset(Areas.Act4.Chaos_Sanctuary, UnitType.Object, UniqueObjectIds.Diablo_Seal5, ObjectModes.Special2); for (i = 0; i < 10; i += 1) { if (getUnit(1, getLocaleString(2851))) { @@ -49,7 +49,8 @@ function Vizier() { delay(250); } - Attack.clear(10, 0, getLocaleString(2851)); // Grand Vizier of Chaos + Attack.kill(getLocaleString(2851)); // Grand Vizier of Chaos + Pickit.pickItems(); return true; } \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/WPGetter.js b/d2bs/kolbot/libs/bots/WPGetter.js new file mode 100644 index 000000000..d4adbb301 --- /dev/null +++ b/d2bs/kolbot/libs/bots/WPGetter.js @@ -0,0 +1,27 @@ +function WPGetter() { + Town.doChores(); + Town.goToTown(1); + Pather.getWP(me.area); + + var i, access; + + for (i = 0; i < Pather.wpAreas.length; i += 1) { + if (Pather.wpAreas[i] < Areas.Act2.Lut_Gholein) { + access = true; + } else if (Pather.wpAreas[i] >= Areas.Act2.Lut_Gholein && Pather.wpAreas[i] < Areas.Act3.Kurast_Docktown) { + access = Pather.accessToAct(2); + } else if (Pather.wpAreas[i] >= Areas.Act3.Kurast_Docktown && Pather.wpAreas[i] < Areas.Act4.The_Pandemonium_Fortress) { + access = Pather.accessToAct(3); + } else if (Pather.wpAreas[i] >= Areas.Act4.The_Pandemonium_Fortress && Pather.wpAreas[i] < Areas.Act5.Harrogath) { + access = Pather.accessToAct(4); + } else if (Pather.wpAreas[i] >= Areas.Act5.Harrogath) { + access = Pather.accessToAct(5); + } + + if (access && !getWaypoint(i) && Pather.wpAreas[i] !== Areas.Act5.Halls_Of_Pain) { + Pather.getWP(Pather.wpAreas[i]); + } + } + + return true; +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/bots/Wakka.js b/d2bs/kolbot/libs/bots/Wakka.js index 00ac53e8b..59e5ee23e 100644 --- a/d2bs/kolbot/libs/bots/Wakka.js +++ b/d2bs/kolbot/libs/bots/Wakka.js @@ -7,7 +7,15 @@ var stopLvl = 99; function Wakka() { - function AutoLeaderDetect(destination) { // autoleader by Ethic + var i, safeTP, portal, vizClear, seisClear, infClear, tick, diablo, + timeout = 1, // minutes + minDist = 50, + maxDist = 80, + leaderUnit = null, + leaderPartyUnit = null, + leader = ""; + + function autoLeaderDetect(destination) { // autoleader by Ethic var solofail, suspect; do { @@ -21,24 +29,34 @@ function Wakka() { if (suspect.area === destination) { // first player in our party found in destination area... leader = suspect.name; // ... is our leader + + if (suspect.area === Areas.Act5.Throne_Of_Destruction) { + return false; + } + print("ÿc4Wakka: ÿc0Autodetected " + leader); + return true; } - } while (suspect.getNext()); + } while (suspect.getNext()); if (solofail === 0) { // empty game, nothing left to do return false; } 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; - }; + } this.checkMonsters = function (range, dodge) { var monList = [], - monster = getUnit(1); + monster = getUnit(UnitType.NPC); if (monster) { do { @@ -59,57 +77,57 @@ function Wakka() { monList.sort(Sort.units); if (getDistance(me, monList[0]) < 25 && !checkCollision(me, monList[0], 0x4)) { - Attack.dodge(monList[0], 25, monList); + Attack.deploy(monList[0], 25, 5, 15); } return true; }; this.getLayout = function (seal, value) { - var sealPreset = getPresetUnit(108, 2, seal); + var sealPreset = getPresetUnit(Areas.Act4.Chaos_Sanctuary, UnitType.Object, seal); if (!seal) { throw new Error("Seal preset not found. Can't continue."); } switch (seal) { - case 396: + case UniqueObjectIds.Diablo_Seal5: if (sealPreset.roomy * 5 + sealPreset.y === value) { return 1; } - break; - case 394: - case 392: + break; + case UniqueObjectIds.Diablo_Seal3: + case UniqueObjectIds.Diablo_Seal1: if (sealPreset.roomx * 5 + sealPreset.x === value) { return 1; } - break; + break; } return 2; }; this.getCoords = function () { - this.vizCoords = this.getLayout(396, 5275) === 1 ? [7707, 5274] : [7708, 5298]; - this.seisCoords = this.getLayout(394, 7773) === 1 ? [7812, 5223] : [7809, 5193]; - this.infCoords = this.getLayout(392, 7893) === 1 ? [7868, 5294] : [7882, 5306]; + this.vizCoords = this.getLayout(UniqueObjectIds.Diablo_Seal5, 5275) === 1 ? [7707, 5274] : [7708, 5298]; + this.seisCoords = this.getLayout(UniqueObjectIds.Diablo_Seal3, 7773) === 1 ? [7812, 5223] : [7809, 5193]; + this.infCoords = this.getLayout(UniqueObjectIds.Diablo_Seal1, 7893) === 1 ? [7868, 5294] : [7882, 5306]; }; this.checkBoss = function (name) { var i, boss, - glow = getUnit(2, 131); + glow = getUnit(UnitType.Object, UniqueObjectIds.Vile_Dog_Afterglow); if (glow) { for (i = 0; i < 10; i += 1) { - if (me.getStat(12) >= stopLvl) { + if (me.getStat(Stats.level) >= stopLvl) { D2Bot.stop(); } - boss = getUnit(1, name); + boss = getUnit(UnitType.NPC, name); - if (boss && boss.mode === 12) { + if (boss && boss.mode === NPCModes.dead) { return true; } @@ -120,17 +138,17 @@ function Wakka() { } return false; - } + }; this.getCorpse = function () { - if (me.mode === 17) { + if (me.mode === PlayerModes.Dead) { me.revive(); } - var i, corpse, + var corpse, rval = false; - corpse = getUnit(0, me.name, 17); + corpse = getUnit(UnitType.Player, me.name, PlayerModes.Dead); if (corpse) { do { @@ -138,7 +156,7 @@ function Wakka() { Pather.moveToUnit(corpse); corpse.interact(); delay(500); - + rval = true; } } while (corpse.getNext()); @@ -148,24 +166,23 @@ function Wakka() { }; this.followPath = function (dest) { - var node, - 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"); } while (path.length > 0) { - if (me.getStat(12) >= stopLvl) { + if (me.getStat(Stats.level) >= stopLvl) { D2Bot.stop(); } - - if (me.mode === 17 || me.inTown) { + + if (me.mode === PlayerModes.Dead || me.inTown) { return false; } if (!leaderUnit || !copyUnit(leaderUnit).x) { - leaderUnit = getUnit(0, leader); + leaderUnit = getUnit(UnitType.Player, leader); } if (leaderUnit) { @@ -204,52 +221,70 @@ function Wakka() { } } - if (Pather.walkTo(path[0].x, path[0].y)) { + if (Pather.moveTo(path[0].x, path[0].y)) { path.shift(); } - - this.getCorpse() + + this.getCorpse(); } return true; }; // start - var i, safeTP, portal, viz, seis, inf, vizClear, seisClear, infClear, path, tick, diablo, - minDist = 40, - maxDist = 80, - leaderUnit = null, - leaderPartyUnit = null, - leader = ""; - Town.goToTown(4); - Town.doChores(); Town.move("portalspot"); - if (AutoLeaderDetect(108)) { + if (Config.Leader) { + leader = Config.Leader; + + for (i = 0; i < 30; i += 1) { + if (Misc.inMyParty(leader)) { + break; + } + + delay(1000); + } + + if (i === 30) { + throw new Error("Wakka: Leader not partied"); + } + } + else { + autoLeaderDetect(Areas.Act4.Chaos_Sanctuary); + } + //print(leader); + Town.doChores(); + + //print("1"); + if (leader) { + //print("2"); while (Misc.inMyParty(leader)) { - if (me.getStat(12) >= stopLvl) { + if (me.getStat(Stats.level) >= stopLvl) { D2Bot.stop(); } switch (me.area) { - case 103: - portal = Pather.getPortal(108, leader); + case Areas.Act4.The_Pandemonium_Fortress: + //portal = Pather.getPortal(108, leader); + portal = Pather.getPortal(Areas.Act4.Chaos_Sanctuary, null); if (portal) { if (!safeTP) { delay(5000); } - Pather.usePortal(108, leader); + //Pather.usePortal(108, leader); + Pather.usePortal(108, null); } break; - case 108: + case Areas.Act4.Chaos_Sanctuary: if (!safeTP) { if (this.checkMonsters(25, false)) { me.overhead("hot tp"); - Pather.usePortal(103, leader); + //Pather.usePortal(103, leader); + Pather.usePortal(Areas.Act4.The_Pandemonium_Fortress, null); this.getCorpse(); break; @@ -271,7 +306,7 @@ function Wakka() { break; } - + if (this.checkBoss(getLocaleString(2851))) { if (!tick) { tick = getTickCount(); @@ -282,7 +317,7 @@ function Wakka() { break; } - + if (!seisClear) { if (!this.followPath(this.seisCoords)) { break; @@ -294,7 +329,7 @@ function Wakka() { break; } - + if (this.checkBoss(getLocaleString(2852))) { if (!tick) { tick = getTickCount(); @@ -331,16 +366,16 @@ function Wakka() { Pather.moveTo(7767, 5263); - diablo = getUnit(1, 243); + diablo = getUnit(UnitType.NPC, UnitClassID.diablo); - if (diablo && (diablo.mode === 0 || diablo.mode === 12)) { + if (diablo && (diablo.mode === NPCModes.death || diablo.mode === NPCModes.dead)) { return true; } break; } - if (me.mode === 17) { + if (me.mode === PlayerModes.Dead) { me.revive(); } diff --git a/d2bs/kolbot/libs/bots/Worldstone.js b/d2bs/kolbot/libs/bots/Worldstone.js new file mode 100644 index 000000000..93fe125cb --- /dev/null +++ b/d2bs/kolbot/libs/bots/Worldstone.js @@ -0,0 +1,22 @@ +/** +* @filename Worldstone.js +* @author kolton +* @desc Clear Worldstone levels +*/ + +function Worldstone() { + Town.doChores(); + Pather.useWaypoint(Areas.Act5.The_Worldstone_Keep_Level_2); + Precast.doPrecast(true); + Attack.clearLevel(Config.ClearType); + + if (Pather.moveToExit(Areas.Act5.The_Worldstone_Keep_Level_1, true)) { + Attack.clearLevel(Config.ClearType); + } + + if (Pather.moveToExit([Areas.Act5.The_Worldstone_Keep_Level_2, Areas.Act5.The_Worldstone_Keep_Level_3], true)) { + Attack.clearLevel(Config.ClearType); + } + + return true; +} \ No newline at end of file diff --git a/d2bs/kolbot/libs/common/Attack.js b/d2bs/kolbot/libs/common/Attack.js index 63b055089..921b64f04 100644 --- a/d2bs/kolbot/libs/common/Attack.js +++ b/d2bs/kolbot/libs/common/Attack.js @@ -10,179 +10,321 @@ var Attack = { // Initialize attacks init: function () { - include("common/CollMap.js"); - - if (include("common/Attacks/" + this.classes[me.classid] + ".js")) { - ClassAttack.init(); + if (Config.Wereform) { + include("common/Attacks/wereform.js"); + } else { + include("common/Attacks/" + this.classes[me.classid] + ".js"); } - if (Config.AttackSkill[1] < 0 && Config.AttackSkill[3] < 0) { + if (Config.AttackSkill[1] < 0 || Config.AttackSkill[3] < 0) { showConsole(); - print("ÿc1No attack skills set. Don't expect your bot to attack."); + print("ÿc1Bad attack config. Don't expect your bot to attack."); } - if (me.gametype === 1) { + if (me.gametype === GameType.Expansion) { this.checkInfinity(); + this.getCharges(); + } + }, + + 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) { + Skill.charges = []; + } + + var i, stats, + item = me.getItem(-1, ItemModes.Item_equipped_self_or_merc); + + if (item) { + do { + stats = item.getStat(-2); + + if (stats.hasOwnProperty(204)) { + if (stats[204] instanceof Array) { + for (i = 0; i < stats[204].length; i += 1) { + if (stats[204][i] !== undefined) { + Skill.charges.push({ + unit: copyUnit(item), + gid: item.gid, + skill: stats[204][i].skill, + level: stats[204][i].level, + charges: stats[204][i].charges, + maxcharges: stats[204][i].maxcharges + }); + } + } + } else { + Skill.charges.push({ + unit: copyUnit(item), + gid: item.gid, + skill: stats[204].skill, + level: stats[204].level, + charges: stats[204].charges, + maxcharges: stats[204].maxcharges + }); + } + } + } while (item.getNext()); } + + return true; }, // Check if player or his merc are using Infinity, and adjust resistance checks based on that checkInfinity: function () { - var i, merc, items; + var i, merc, item; - for (i = 0; !merc && i < 3; i += 1) { + for (i = 0; i < 3; i += 1) { merc = me.getMerc(); + if (merc) { + break; + } + delay(50); } // Check merc infinity - if (merc) { - items = merc.getItems(); - - if (items) { - for (i = 0; i < items.length; i += 1) { - if (items[i].getPrefix(20566)) { - //print("Infinity detected"); + item = merc.getItem(); + if (item) { + do { + if (item.getPrefix(20566)) { this.infinity = true; return true; } - } + } while (item.getNext()); } } // Check player infinity + item = me.getItem(-1, ItemModes.Item_equipped_self_or_merc); - items = me.findItems(-1, 1); - - if (items) { - for (i = 0; i < items.length; i += 1) { - if (items[i].getPrefix(20566)) { - //print("Infinity detected"); - + if (item) { + do { + if (item.getPrefix(20566)) { this.infinity = true; return true; } - } + } while (item.getNext()); } return false; }, - // Kill a monster based on its classId + // Kill a monster based on its classId, can pass a unit as well kill: function (classId) { if (Config.AttackSkill[1] < 0) { return false; } - var i, target, - dodgeList = [], + var i, target, gid, + errorInfo = "", attackCount = 0; - for (i = 0; i < 3; i += 1) { - target = getUnit(1, classId); + if (typeof classId === "object") { + target = classId; + } - if (target) { - break; - } + for (i = 0; !target && i < 5; i += 1) { + target = getUnit(1, classId); - delay(50); + delay(200); } if (!target) { throw new Error("Attack.kill: Target not found"); } + gid = target.gid; + if (Config.MFLeader) { Pather.makePortal(); say("kill " + classId); } while (attackCount < 300 && this.checkMonster(target) && this.skipCheck(target)) { - if (Config.Dodge) { - if (attackCount % 5 === 0) { - dodgeList = this.buildDodgeList(); - } + Misc.townCheck(); - if (dodgeList.length) { - dodgeList.sort(Sort.units); + if (!target || !copyUnit(target).x) { // Check if unit got invalidated, happens if necro raises a skeleton from the boss's corpse. + target = getUnit(UnitType.NPC, -1, -1, gid); - if (getDistance(me, dodgeList[0]) < 13) { - this.dodge(target, 15, dodgeList); - } + if (!target) { + break; } } - Misc.townCheck(true); + if (Config.Dodge && me.hp * 100 / me.hpmax <= Config.DodgeHP) { + this.deploy(target, Config.DodgeRange, 5, 9); + } + + if (Config.MFSwitchPercent && target.hp / 128 * 100 < Config.MFSwitchPercent) { + Precast.weaponSwitch(Math.abs(Config.MFSwitch)); + } + + 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; + } + + attackCount += 1; + } + + if (attackCount === 300) { + errorInfo = " (attackCount exceeded)"; + } + + if (Config.MFSwitchPercent) { + Precast.weaponSwitch(Math.abs(Config.MFSwitch - 1)); + } + + ClassAttack.afterAttack(); + + if (!target || !copyUnit(target).x) { + return true; + } + + if (target.hp > 0 && target.mode !== NPCModes.death && target.mode !== NPCModes.dead) { + throw new Error("Failed to kill " + target.name + errorInfo); + } + + return true; + }, + + hurt: function (classId, percent) { + var i, target, + attackCount = 0; + + for (i = 0; i < 5; i += 1) { + target = getUnit(UnitType.NPC, classId); + + if (target) { + break; + } + + delay(200); + } - if (ClassAttack.doAttack(target, attackCount % 15 === 0) < 2) { + while (attackCount < 300 && Attack.checkMonster(target) && Attack.skipCheck(target)) { + if (!ClassAttack.doAttack(target, attackCount % 15 === 0)) { break; } - if (!copyUnit(target).x) { // Check if unit got invalidated, happens if necro raises a skeleton from the boss's corpse. + if (!copyUnit(target).x) { return true; } attackCount += 1; + + if (target.hp * 100 / 128 <= percent) { + break; + } } - return (target.mode === 0 || target.mode === 12); + return true; + }, + + getScarinessLevel: function (unit) { + var scariness = 0, ids = [UnitClassID.fallenshaman1, UnitClassID.fallenshaman2, UnitClassID.fallenshaman3, UnitClassID.fallenshaman4, UnitClassID.fallenshaman5, + UnitClassID.unraveler1, UnitClassID.unraveler2, UnitClassID.unraveler3, UnitClassID.unraveler4, UnitClassID.unraveler5, UnitClassID.fetishshaman1, UnitClassID.fetishshaman2, + UnitClassID.fetishshaman3, UnitClassID.fetishshaman4, UnitClassID.fetishshaman5, UnitClassID.vilemother1, UnitClassID.vilemother2, UnitClassID.vilemother3, + UnitClassID.fallenshaman6, UnitClassID.fallenshaman7, UnitClassID.fallenshaman8, UnitClassID.fetishshaman6, UnitClassID.fetishshaman7, UnitClassID.fetishshaman8, + UnitClassID.unraveler6, UnitClassID.unraveler7, UnitClassID.unraveler8, UnitClassID.unraveler9, UnitClassID.vilemother4, UnitClassID.vilemother5]; + + // Only handling monsters for now + if (unit.type !== 1) { + return undefined; + } + + // Minion + if (unit.spectype & 0x08) { + scariness += 1; + } + + // Champion + if (unit.spectype & 0x02) { + scariness += 2; + } + + // Boss + if (unit.spectype & 0x04) { + scariness += 4; + } + + // Summoner or the like + if (ids.indexOf(unit.classid) > -1) { + scariness += 8; + } + + return scariness; }, // Clear monsters in a section based on range and spectype or clear monsters around a boss monster clear: function (range, spectype, bossId, sortfunc, pickit) { // probably going to change to passing an object + while (!me.gameReady) { + delay(40); + } + if (Config.MFLeader && !!bossId) { Pather.makePortal(); say("clear " + bossId); } - switch (arguments.length) { - case 0: + if (range === undefined) { range = 25; - spectype = 0; - bossId = false; - sortfunc = false; - pickit = true; + } - break; - case 1: + if (spectype === undefined) { spectype = 0; - bossId = false; - sortfunc = false; - pickit = true; + } - break; - case 2: + if (bossId === undefined) { bossId = false; - sortfunc = false; - pickit = true; + } - break; - case 3: + if (sortfunc === undefined) { sortfunc = false; - pickit = true; + } - break; - case 4: + if (pickit === undefined) { pickit = true; - - break; } if (typeof (range) !== "number") { throw new Error("Attack.clear: range must be a number."); } - var i, boss, orgx, orgy, target, result, monsterList, - dodgeList = [], + var i, boss, orgx, orgy, target, result, monsterList, start, gidAttack = [], attackCount = 0; - if (Config.AttackSkill[1] < 0 || Config.AttackSkill[me.classid === 4 ? 2 : 3] < 0) { + if (Config.AttackSkill[1] < 0 || Config.AttackSkill[3] < 0) { return false; } @@ -191,10 +333,10 @@ var Attack = { } if (bossId) { - for (i = 0; !boss && i < 3; i += 1) { - boss = getUnit(1, bossId); + for (i = 0; !boss && i < 5; i += 1) { + boss = bossId > 999 ? getUnit(UnitType.NPC, -1, -1, bossId) : getUnit(UnitType.NPC, bossId); - delay(50); + delay(200); } if (!boss) { @@ -209,40 +351,40 @@ var Attack = { } monsterList = []; - target = getUnit(1); + target = getUnit(UnitType.NPC); if (target) { do { - if (this.checkMonster(target) && this.skipCheck(target)) { + if ((!spectype || (target.spectype & spectype)) && this.checkMonster(target) && this.skipCheck(target)) { + // Speed optimization - don't go through monster list until there's at least one within clear range + if (!start && getDistance(target, orgx, orgy) <= range && + (me.getSkill(Skills.Sorceress.Teleport, 1) || !Scripts.Follower || !checkCollision(me, target, 0x1))) { + start = true; + } + monsterList.push(copyUnit(target)); } } while (target.getNext()); } - while (monsterList.length > 0) { - if (me.mode === 17) { + while (start && monsterList.length > 0 && attackCount < 300) { + if (boss) { + orgx = boss.x; + orgy = boss.y; + } + + if (me.dead) { return false; } - monsterList.sort(Sort.units); + //monsterList.sort(Sort.units); monsterList.sort(sortfunc); target = copyUnit(monsterList[0]); - if (typeof target.x !== "undefined" && Math.abs(orgx - target.x) <= range && Math.abs(orgy - target.y) <= range && (!spectype || (target.spectype & spectype)) && this.checkMonster(target) && (me.getSkill(54, 1) || !checkCollision(me, target, 0x1))) { - if (Config.Dodge) { - if (attackCount % 5 === 0) { - dodgeList = this.buildDodgeList(); - } - - if (attackCount > 0 && dodgeList.length > 0) { - dodgeList.sort(Sort.units); - - if (getDistance(me, dodgeList[0]) < 13) { - //this.dodge(dodgeList[0], 15, dodgeList); - this.dodge(target, 15, dodgeList); - } - } + if (target.x !== undefined && (getDistance(target, orgx, orgy) <= range || (this.getScarinessLevel(target) > 7 && getDistance(me, target) <= range)) && this.checkMonster(target)) { + if (Config.Dodge && me.hp * 100 / me.hpmax <= Config.DodgeHP) { + this.deploy(target, Config.DodgeRange, 5, 9); } Misc.townCheck(true); @@ -250,48 +392,60 @@ 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; + gidAttack[i].attacks += 1; + attackCount += 1; + + // Desync/bad position handler + switch (Config.AttackSkill[(target.spectype & 0x7) ? 1 : 3]) { + case Skills.Paladin.Blessed_Hammer: + //print(gidAttack[i].name + " " + gidAttack[i].attacks); + + // 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); + } - if (gidAttack[i].attacks > 12) { - print("ÿc1Skipping " + target.name); - monsterList.shift(); + 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 !== Areas.Act5.Throne_Of_Destruction && !(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) { + if (target.mode === NPCModes.death || target.mode === NPCModes.dead || Config.FastPick === 2) { Pickit.fastPick(); } - - break; - default: - return false; + } else { + monsterList.shift(); } } else { monsterList.shift(); } } - ClassAttack.afterAttack(); - this.openChests(range); + ClassAttack.afterAttack(pickit); + this.openChests(range, orgx, orgy); if (attackCount > 0 && pickit) { Pickit.pickItems(); @@ -301,16 +455,44 @@ 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, classid); + monster = getUnit(UnitType.NPC); - if (monster) { - do { - if (getDistance(me, monster) <= range && (!spectype || (monster.spectype & spectype)) && this.checkMonster(monster)) { - monsterList.push(copyUnit(monster)); - } - } while (monster.getNext()); + if (range === undefined) { + range = 25; + } + + if (!center) { + center = me; + } + + switch (typeof classid) { + case "number": + case "string": + monster = getUnit(UnitType.NPC, classid); + + if (monster) { + do { + 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()); + } + + break; + case "object": + monster = getUnit(UnitType.NPC); + + if (monster) { + do { + 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()); + } + + break; } if (!monsterList.length) { @@ -321,37 +503,46 @@ var Attack = { }, // Clear an already formed array of monstas - clearList: function (list, sortfunc) { - var i, target, result, - dodgeList = [], + clearList: function (mainArg, sortFunc, refresh) { + var i, target, result, monsterList, gidAttack = [], - attackCount = 0, - monsterList = list.slice(0); + attackCount = 0; - if (!sortfunc) { - sortfunc = this.sortMonsters; + switch (typeof mainArg) { + case "function": + monsterList = mainArg.call(); + + break; + case "object": + monsterList = mainArg.slice(0); + + break; + case "boolean": // false from Attack.getMob() + return false; + default: + throw new Error("clearList: Invalid argument"); } - while (monsterList.length > 0) { - monsterList.sort(Sort.units); - monsterList.sort(sortfunc); + if (!sortFunc) { + sortFunc = this.sortMonsters; + } - target = copyUnit(monsterList[0]); + while (monsterList.length > 0 && attackCount < 300) { + if (refresh && attackCount > 0 && attackCount % refresh === 0) { + monsterList = mainArg.call(); + } - if (typeof target.x !== "undefined" && this.checkMonster(target)) { - if (Config.Dodge) { - if (attackCount % 5 === 0) { - dodgeList = this.buildDodgeList(); - } + if (me.dead) { + return false; + } - if (attackCount > 0 && dodgeList.length > 0) { - dodgeList.sort(Sort.units); + monsterList.sort(sortFunc); - if (getDistance(me, dodgeList[0]) < 13) { - //this.dodge(dodgeList[0], 15, dodgeList); - this.dodge(target, 15, dodgeList); - } - } + target = copyUnit(monsterList[0]); + + if (target.x !== undefined && this.checkMonster(target)) { + if (Config.Dodge && me.hp * 100 / me.hpmax <= Config.DodgeHP) { + this.deploy(target, Config.DodgeRange, 5, 9); } Misc.townCheck(true); @@ -359,43 +550,57 @@ 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}); + } + + 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 > 12) { - print("ÿc1Skipping " + target.name); - monsterList.shift(); - } + // Skip non-unique monsters after 15 attacks, except in Throne of Destruction + if (me.area !== Areas.Act5.Throne_Of_Destruction && !(target.spectype & 0x7) && gidAttack[i].attacks > 15) { + print("ÿc1Skipping " + target.name + " " + target.gid + " " + gidAttack[i].attacks); + monsterList.shift(); } attackCount += 1; - break; - default: - return false; + if (target.mode === NPCModes.death || target.mode === NPCModes.dead || Config.FastPick === 2) { + Pickit.fastPick(); + } + } else { + monsterList.shift(); } } else { monsterList.shift(); } } - ClassAttack.afterAttack(); + ClassAttack.afterAttack(true); this.openChests(30); if (attackCount > 0) { @@ -405,13 +610,128 @@ var Attack = { return true; }, + securePosition: function (x, y, range, timer, skipBlocked, special) { + /*if (arguments.length < 4) { + throw new Error("securePosition needs 4 arguments"); + }*/ + + var monster, monList, tick; + + if (skipBlocked === true) { + skipBlocked = 0x4; + } + + while (true) { + if (getDistance(me, x, y) > 5) { + Pather.moveTo(x, y); + } + + monster = getUnit(UnitType.NPC); + monList = []; + + if (monster) { + do { + if (getDistance(monster, x, y) <= range && this.checkMonster(monster) && this.canAttack(monster) && + (!skipBlocked || !checkCollision(me, monster, skipBlocked)) && + ((me.classid === ClassID.Sorceress && me.getSkill(Skills.Sorceress.Teleport, 1)) || me.getStat(Stats.item_nonclassskill, Skills.Sorceress.Teleport) || !checkCollision(me, monster, 0x1))) { + monList.push(copyUnit(monster)); + } + } while (monster.getNext()); + } + + if (!monList.length) { + if (!tick) { + tick = getTickCount(); + } + + // only return if it's been safe long enough + if (getTickCount() - tick >= timer) { + return true; + } + } else { + this.clearList(monList); + + // reset the timer when there's monsters in range + if (tick) { + tick = false; + } + } + + if (special) { + switch (me.classid) { + case ClassID.Paladin: // Paladin Redemption addon + if (me.getSkill(Skills.Paladin.Redemption, 1)) { + Skill.setSkill(Skills.Paladin.Redemption, 0); + delay(1000); + } + + break; + } + } + + delay(100); + } + + return true; + }, + // Draw lines around a room on minimap - /*markRoom: function (room, color) { - new Line(room.x * 5, room.y * 5, room.x * 5, room.y * 5 + room.ysize, color, true); - new Line(room.x * 5, room.y * 5, room.x * 5 + room.xsize, room.y * 5, color, true); - new Line(room.x * 5 + room.xsize, room.y * 5, room.x * 5 + room.xsize, room.y * 5 + room.ysize, color, true); - new Line(room.x * 5, room.y * 5 + room.ysize, room.x * 5 + room.xsize, room.y * 5 + room.ysize, color, true); - },*/ + markRoom: function (room, color) { + var arr = []; + + arr.push(new Line(room.x * 5, room.y * 5, room.x * 5, room.y * 5 + room.ysize, color, true)); + arr.push(new Line(room.x * 5, room.y * 5, room.x * 5 + room.xsize, room.y * 5, color, true)); + arr.push(new Line(room.x * 5 + room.xsize, room.y * 5, room.x * 5 + room.xsize, room.y * 5 + room.ysize, color, true)); + arr.push(new Line(room.x * 5, room.y * 5 + room.ysize, room.x * 5 + room.xsize, room.y * 5 + room.ysize, color, true)); + }, + + countUniques: function () { + if (!this.uniques) { + this.uniques = 0; + } + + if (!this.ignoredGids) { + this.ignoredGids = []; + } + + var monster = getUnit(1); + + if (monster) { + do { + if ((monster.spectype & 0x5) && this.ignoredGids.indexOf(monster.gid) === -1) { + this.uniques += 1; + this.ignoredGids.push(monster.gid); + } + } while (monster.getNext()); + } + }, + + storeStatistics: function (area) { + var obj; + + if (!FileTools.exists("statistics.json")) { + Misc.fileAction("statistics.json", 1, "{}"); + } + + obj = JSON.parse(Misc.fileAction("statistics.json", 0)); + + if (obj) { + if (obj[area] === undefined) { + obj[area] = { + runs: 0, + averageUniques: 0 + }; + } + + obj[area].averageUniques = ((obj[area].averageUniques * obj[area].runs + this.uniques) / (obj[area].runs + 1)).toFixed(4); + obj[area].runs += 1; + + Misc.fileAction("statistics.json", 1, JSON.stringify(obj)); + } + + this.uniques = 0; + this.ignoredGids = []; + }, // Clear an entire area based on monster spectype clearLevel: function (spectype) { @@ -432,7 +752,7 @@ var Attack = { return false; } - if (arguments.length < 1) { + if (spectype === undefined) { spectype = 0; } @@ -459,30 +779,67 @@ var Attack = { rooms.sort(RoomSort); room = rooms.shift(); - //print("myroom: " + myRoom[0] + ", " + myRoom[1] + " nextroom: " + room[0] + ", " + room[1]); - - result = Pather.getNearestWalkable(room[0], room[1], 15, 2); + result = Pather.getNearestWalkable(room[0], room[1], 18, 3); if (result) { - //this.markRoom(getRoom(room[0], room[1]), 0x84); - Pather.moveTo(result[0], result[1], 3); + Pather.moveTo(result[0], result[1], 3, spectype); + //this.countUniques(); - if (!this.clear(30, spectype)) { - return false; + if (!this.clear(40, spectype)) { + break; } - }/* else { - this.markRoom(getRoom(room[0], room[1]), 0x62); - }*/ + } } - CollMap.reset(); + //this.storeStatistics(Pather.getAreaName(me.area)); return true; }, // Sort monsters based on distance, spectype and classId (summoners are attacked first) sortMonsters: function (unitA, unitB) { - var 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]; + // No special sorting for were-form + if (Config.Wereform) { + return getDistance(me, unitA) - getDistance(me, unitB); + } + + // Barb optimization + if (me.classid === ClassID.Barbarian) { + if (!Attack.checkResist(unitA, Attack.getSkillElement(Config.AttackSkill[(unitA.spectype & 0x7) ? 1 : 3]))) { + return 1; + } + + if (!Attack.checkResist(unitB, Attack.getSkillElement(Config.AttackSkill[(unitB.spectype & 0x7) ? 1 : 3]))) { + return -1; + } + } + + var ids = [UnitClassID.fallenshaman1, UnitClassID.fallenshaman2, UnitClassID.fallenshaman3, UnitClassID.fallenshaman4, UnitClassID.fallenshaman5, + UnitClassID.unraveler1, UnitClassID.unraveler2, UnitClassID.unraveler3, UnitClassID.unraveler4, UnitClassID.unraveler5, + UnitClassID.fetishshaman1, UnitClassID.fetishshaman2, UnitClassID.fetishshaman3, UnitClassID.fetishshaman4, UnitClassID.fetishshaman5, + UnitClassID.vilemother1, UnitClassID.vilemother2, UnitClassID.vilemother3, + UnitClassID.fallenshaman6, UnitClassID.fallenshaman7, UnitClassID.fallenshaman8, + UnitClassID.fetishshaman6, UnitClassID.fetishshaman7, UnitClassID.fetishshaman8, + UnitClassID.unraveler6, UnitClassID.unraveler7, UnitClassID.unraveler8, UnitClassID.unraveler9, + UnitClassID.vilemother4, UnitClassID.vilemother5]; + + + if (me.area !== Areas.Act2.Claw_Viper_Temple_Level_2 && ids.indexOf(unitA.classid) > -1 && ids.indexOf(unitB.classid) > -1) { + // Kill "scary" uniques first (like Bishibosh) + if ((unitA.spectype & SpecType.Boss) && (unitB.spectype & SpecType.Boss)) { + return getDistance(me, unitA) - getDistance(me, unitB); + } + + if (unitA.spectype & SpecType.Boss) { + return -1; + } + + if (unitB.spectype & SpecType.Boss) { + return 1; + } + + return getDistance(me, unitA) - getDistance(me, unitB); + } if (ids.indexOf(unitA.classid) > -1) { return -1; @@ -493,6 +850,10 @@ var Attack = { } if (Config.BossPriority) { + if ((unitA.spectype & 0x5) && (unitB.spectype & 0x5)) { + return getDistance(me, unitA) - getDistance(me, unitB); + } + if (unitA.spectype & 0x5) { return -1; } @@ -502,14 +863,14 @@ var Attack = { } } - return 1; + return getDistance(me, unitA) - getDistance(me, unitB); }, // Check if a set of coords is valid/accessable validSpot: function (x, y) { var result; - if (!me.area) { // Just in case + if (!me.area || !x || !y) { // Just in case return false; } @@ -520,7 +881,7 @@ var Attack = { } // Avoid non-walkable spots, objects - if (result === undefined || result & 0x1 || result & 0x400) { + if (result === undefined || (result & 0x1) || (result & 0x400)) { return false; } @@ -528,118 +889,188 @@ 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(UnitType.Object); - 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; }, - // Make a list of monsters that will be monitored for dodging - buildDodgeList: function () { - var ignoreList = [243, 544], - monster = getUnit(1), - list = []; + buildMonsterList: function () { + var monster, + monList = []; + + monster = getUnit(1); if (monster) { do { - if (ignoreList.indexOf(monster.classid) === -1 && this.checkMonster(monster)) { - list.push(copyUnit(monster)); + if (this.checkMonster(monster)) { + monList.push(copyUnit(monster)); } } while (monster.getNext()); } - return list; + return monList; }, - // Move away from a nearby monster into a more safe position - dodge: function (unit, distance, list) { - var i, j, coordx, coordy, count, - maxcount = 99, - coords = [], - goodCoords = [], - angle = Math.round(Math.atan2(me.y - unit.y, me.x - unit.x) * 180 / Math.PI), - angles = [0, 30, -30, 60, -60, 90, -90, 120, -120, 150, -150, 180]; + deploy: function (unit, distance, spread, range) { + if (arguments.length < 4) { + throw new Error("deploy: Not enough arguments supplied"); + } - // step 1 - build possible dodge positions based on angles + var i, grid, index, currCount, + tick = getTickCount(), + monList = [], + count = 999, + idealPos = { + x: Math.round(Math.cos(Math.atan2(me.y - unit.y, me.x - unit.x)) * Config.DodgeRange + unit.x), + y: Math.round(Math.sin(Math.atan2(me.y - unit.y, me.x - unit.x)) * Config.DodgeRange + unit.y) + }; - for (i = 0; i < angles.length; i = i + 1) { - coordx = Math.round((Math.cos((angle + angles[i]) * Math.PI / 180)) * distance + unit.x); - coordy = Math.round((Math.sin((angle + angles[i]) * Math.PI / 180)) * distance + unit.y); + monList = this.buildMonsterList(); - if (this.validSpot(coordx, coordy)) { - coords.push([coordx, coordy]); - } + monList.sort(Sort.units); + + if (this.getMonsterCount(me.x, me.y, 15, monList) === 0) { + return true; } - if (coords.length === 0) { // no valid positions - don't move - me.overhead("Can't dodge :("); + CollMap.getNearbyRooms(unit.x, unit.y); - return true; + grid = this.buildGrid(unit.x - distance, unit.x + distance, unit.y - distance, unit.y + distance, spread); + + //print("Grid build time: " + (getTickCount() - tick)); + + if (!grid.length) { + return false; } - coords.sort(Sort.points); + 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(b.x, b.y, unit.x, unit.y) - getDistance(a.x, a.y, unit.x, unit.y); + } - for (i = 0; i < coords.length; i += 1) { - count = 0; + grid.sort(sortGrid); - for (j = 0; j < list.length; j += 1) { - if (list[j].hp > 0 && getDistance(list[j].x, list[j].y, coords[i][0], coords[i][1]) < 13) { - count += 1; - } - } + for (i = 0; i < grid.length; i += 1) { + if (!(CollMap.getColl(grid[i].x, grid[i].y, true) & 0x1) && !CollMap.checkColl(unit, {x: grid[i].x, y: grid[i].y}, 0x4)) { + currCount = this.getMonsterCount(grid[i].x, grid[i].y, range, monList); - if (count < maxcount) { - goodCoords = [coords[i][0], coords[i][1]]; - maxcount = count; + if (currCount < count) { + index = i; + count = currCount; + } - if (count === 0) { + if (currCount === 0) { break; } } } - if (goodCoords.length > 0) { // just in case goodCoords is empty (shouldn't happen) - if (getDistance(me, goodCoords[0], goodCoords[1]) < 4) { // close enough - return true; + //print("Safest spot with " + count + " monsters."); + + if (typeof index === "number") { + //print("Dodge build time: " + (getTickCount() - tick)); + + return Pather.moveTo(grid[index].x, grid[index].y, 0); + } + + return false; + }, + + getMonsterCount: function (x, y, range, list) { + var i, + fire, + count = 0, + ignored = [UnitClassID.diablo]; + + for (i = 0; i < list.length; i += 1) { + if (ignored.indexOf(list[i].classid) === -1 && this.checkMonster(list[i]) && getDistance(x, y, list[i].x, list[i].y) <= range) { + count += 1; } + } + + fire = getUnit(UnitType.Object, "fire"); - me.overhead("Dodge!"); - Pather.moveTo(goodCoords[0], goodCoords[1], 3); + if (fire) { + do { + if (getDistance(x, y, fire.x, fire.y) <= 4) { + count += 100; + } + } while (fire.getNext()); } - return true; + return count; + }, + + buildGrid: function (xmin, xmax, ymin, ymax, spread) { + if (xmin >= xmax || ymin >= ymax || spread < 1) { + throw new Error("buildGrid: Bad parameters"); + } + + var i, j, coll, + grid = []; + + for (i = xmin; i <= xmax; i += spread) { + for (j = ymin; j <= ymax; j += spread) { + coll = CollMap.getColl(i, j, true); + + if (typeof coll === "number") { + grid.push({x: i, y: j, coll: coll}); + } + } + } + + return grid; }, // Check if a monster is attackable checkMonster: function (unit) { - if (!unit) { + if (!unit || !copyUnit(unit).x) { return false; } - if (unit.type === 0 && unit.mode !== 17) { // Player - return true; + if (unit.area !== me.area) { + return false; } - if (unit.mode === 0 || unit.mode === 12) { // Dead monster - return false; + if (unit.type === UnitType.Player && unit.mode !== PlayerModes.Dead) { // Player + return true; } - if (unit.getStat(172) === 2) { // Friendly monster/NPC + if (unit.hp === 0 || unit.mode === NPCModes.death || unit.mode === NPCModes.dead) { // Dead monster return false; } - if (unit.classid === 543 && me.area === 131) { // Baal in Throne + if (unit.getStat(Stats.alignment) === 2) { // Friendly monster/NPC return false; } @@ -648,35 +1079,40 @@ var Attack = { } switch (unit.classid) { - case 110: // Vultures - case 111: - case 112: - case 113: - case 114: - case 179: // An evil force - cow (lol) + case UnitClassID.cow: // An evil force - cow (lol) return false; - case 608: - if (unit.mode === 8) { // Flying + case UnitClassID.baalthrone: // Baal in Throne + if (me.area === Areas.Act5.Throne_Of_Destruction) { return false; } - break; - case 68: // Sand Maggots - case 69: - case 70: - case 71: - case 72: - case 679: - case 258: // Water Watchers - case 259: - case 260: - case 261: - case 262: - case 263: - if (unit.mode === 14) { // Submerged/Burrowed + + case UnitClassID.vulture1: // Vultures + case UnitClassID.vulture2: + case UnitClassID.vulture3: + case UnitClassID.vulture4: + case UnitClassID.mosquito1: + case UnitClassID.vulture5: + if (unit.mode === NPCModes.skill1) { // Flying return false; } + break; + case UnitClassID.sandmaggot1: // Sand Maggots + case UnitClassID.sandmaggot2: + case UnitClassID.sandmaggot3: + case UnitClassID.sandmaggot4: + case UnitClassID.sandmaggot5: + case UnitClassID.sandmaggot6: + case UnitClassID.tentacle1: // Water Watchers + case UnitClassID.tentacle2: + case UnitClassID.tentacle3: + case UnitClassID.tentaclehead1: + case UnitClassID.tentaclehead2: + case UnitClassID.tentaclehead3: + if (unit.mode === NPCModes.sequence) { // Submerged/Burrowed + return false; + } break; } @@ -684,7 +1120,7 @@ var Attack = { }, skipCheck: function (unit) { - if (me.area === 131) { + if (me.area === Areas.Act5.Throne_Of_Destruction) { return true; } @@ -750,13 +1186,15 @@ EnchantLoop: // Skip enchanted monsters for (j = 0; j < tempArray.length; j += 1) { if (!unit.getEnchant(tempArray[j])) { - continue EnchantLoop; + break; } } - //print("ÿc1Skipping " + unit.name + " (enchant skip -" + Config.SkipEnchant[i] + ")"); + if (j === tempArray.length) { + //print("Skip Enchanted: " + unit.name); - return false; + return false; + } } ImmuneLoop: // Skip immune monsters @@ -765,13 +1203,13 @@ ImmuneLoop: // Skip immune monsters for (j = 0; j < tempArray.length; j += 1) { if (this.checkResist(unit, tempArray[j])) { // Infinity calculations are built-in - continue ImmuneLoop; + break; } } - //print("ÿc1Skipping " + unit.name + " (immunity skip -" + Config.SkipImmune[i] + ")"); - - return false; + if (j === tempArray.length) { + return false; + } } AuraLoop: // Skip monsters with auras @@ -780,43 +1218,43 @@ AuraLoop: // Skip monsters with auras switch (Config.SkipAura[i].toLowerCase()) { case "fanaticism": - if (unit.getState(49)) { + if (unit.getState(States.FANATICISM)) { rval = false; } break; case "might": - if (unit.getState(33)) { + if (unit.getState(States.MIGHT)) { rval = false; } break; case "holy fire": - if (unit.getState(35)) { + if (unit.getState(States.HOLYFIRE)) { rval = false; } break; case "blessed aim": - if (unit.getState(40)) { + if (unit.getState(States.BLESSEDAIM)) { rval = false; } break; case "conviction": - if (unit.getState(28)) { + if (unit.getState(States.CONVICTION)) { rval = false; } break; case "holy freeze": - if (unit.getState(43)) { + if (unit.getState(States.HOLYWIND)) { rval = false; } break; case "holy shock": - if (unit.getState(46)) { + if (unit.getState(States.HOLYSHOCK)) { rval = false; } @@ -824,8 +1262,6 @@ AuraLoop: // Skip monsters with auras } if (!rval) { - //print("ÿc1Skipping " + unit.name + " (aura skip -" + Config.SkipAura[i] + ")"); - return false; } } @@ -838,11 +1274,13 @@ AuraLoop: // Skip monsters with auras this.elements = ["physical", "fire", "lightning", "magic", "cold", "poison", "none"]; switch (skillId) { - case 74: // Corpse Explosion - case 147: // Frenzy + case Skills.Necromancer.Corpse_Explosion: // Corpse Explosion + case Skills.Barbarian.Concentrate: // Concentrate + case Skills.Barbarian.Frenzy: // Frenzy + case Skills.Assassin.Mind_Blast: // Minge Blast case 500: // Summoner return "physical"; - case 101: // Holy Bolt + case Skills.Paladin.Holy_Bolt: // Holy Bolt return "holybolt"; // no need to use this.elements array because it returns before going over the array } @@ -857,23 +1295,23 @@ AuraLoop: // Skip monsters with auras // Get a monster's resistance to specified element getResist: function (unit, type) { - if (unit.type === 0) { // player + if (unit.type === UnitType.Player) { // player return 0; } switch (type) { case "physical": - return unit.getStat(36); + return unit.getStat(Stats.damageresist); case "fire": - return unit.getStat(39); + return unit.getStat(Stats.fireresist); case "lightning": - return unit.getStat(41); + return unit.getStat(Stats.lightresist); case "magic": - return unit.getStat(37); + return unit.getStat(Stats.magicresist); case "cold": - return unit.getStat(43); + return unit.getStat(Stats.coldresist); case "poison": - return unit.getStat(45); + return unit.getStat(Stats.poisonresist); case "none": return 0; case "holybolt": // check if a monster is undead @@ -888,37 +1326,70 @@ AuraLoop: // Skip monsters with auras }, // Check if a monster is immune to specified attack type - checkResist: function (unit, type) { - if (unit.type === 0) { // player + checkResist: function (unit, val, maxres) { + // Ignore player resistances + if (unit.type === UnitType.Player) { return true; } - if (this.infinity && ["fire", "lightning", "cold"].indexOf(type) > -1) { - if (!unit.getState(28)) { - return this.getResist(unit, type) < 117; + var damageType = typeof val === "number" ? this.getSkillElement(val) : val; + + if (maxres === undefined) { + maxres = 100; + } + + // 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(States.CONVICTION)) { + return this.getResist(unit, damageType) < 117; + } + + return this.getResist(unit, damageType) < maxres; + } + + return this.getResist(unit, damageType) < maxres; + }, + + // Check if we have valid skills to attack a monster + canAttack: function (unit) { + if (unit.type === UnitType.NPC) { + if (unit.spectype & 0x7) { // Unique/Champion + if (Attack.checkResist(unit, this.getSkillElement(Config.AttackSkill[1])) || Attack.checkResist(unit, this.getSkillElement(Config.AttackSkill[2]))) { + return true; + } } else { - return this.getResist(unit, type) < 100; + if (Attack.checkResist(unit, this.getSkillElement(Config.AttackSkill[3])) || Attack.checkResist(unit, this.getSkillElement(Config.AttackSkill[4]))) { + return true; + } + } + + if (Config.AttackSkill.length === 7) { + return Attack.checkResist(unit, this.getSkillElement(Config.AttackSkill[5])) || Attack.checkResist(unit, this.getSkillElement(Config.AttackSkill[6])); } } - return this.getResist(unit, type) < 100; + return false; }, // Detect use of bows/crossbows usingBow: function () { var item; - item = me.getItem(-1, 1); + item = me.getItem(-1, ItemLocation.Equipped); if (item) { do { - if (item.bodylocation === 4 || item.bodylocation === 5) { + if (item.bodylocation === ItemBodyLocation.RIGHT_ARM || item.bodylocation === ItemBodyLocation.LEFT_ARM) { switch (item.itemType) { - case 27: // Bows - case 85: // Amazon Bows - return "bow"; - case 35: // Crossbows - return "crossbow"; + case NTItemTypes.bow: // Bows + case NTItemTypes.amazonbow: // Amazon Bows + return "bow"; + case NTItemTypes.crossbow: // Crossbows + return "crossbow"; } } } while (item.getNext()); @@ -929,50 +1400,89 @@ AuraLoop: // Skip monsters with auras // Find an optimal attack position and move or walk to it getIntoPosition: function (unit, distance, coll, walk) { - if (typeof walk === "undefined") { - walk = false; + if (!unit || !unit.x || !unit.y) { + return false; + } + + if (walk === true) { + walk = 1; + } + + if (distance < 4 && (!unit.hasOwnProperty("mode") || (unit.mode !== NPCModes.death && unit.mode !== NPCModes.dead))) { + //me.overhead("Short range"); + + if (walk) { + if (getDistance(me, unit) > 8 || checkCollision(me, unit, coll)) { + Pather.walkTo(unit.x, unit.y, 3); + } + } else { + Pather.moveTo(unit.x, unit.y, 0); + } + + return !CollMap.checkColl(me, unit, coll); } var n, i, cx, cy, t, coords = [], + fullDistance = distance, + name = unit.hasOwnProperty("name") ? unit.name : "", angle = Math.round(Math.atan2(me.y - unit.y, me.x - unit.x) * 180 / Math.PI), - angles = [0, 45, 90, 135, 180, 225, 270, 305]; + angles = [0, 15, -15, 30, -30, 45, -45, 60, -60, 75, -75, 90, -90, 135, -135, 180]; t = getTickCount(); for (n = 0; n < 3; n += 1) { if (n > 0) { - distance = Math.floor(distance / 2); + distance -= Math.floor(fullDistance / 3 - 1); } for (i = 0; i < angles.length; i += 1) { cx = Math.round((Math.cos((angle + angles[i]) * Math.PI / 180)) * distance + unit.x); cy = Math.round((Math.sin((angle + angles[i]) * Math.PI / 180)) * distance + unit.y); - //if (!(CollMap.getColl(cx, cy) & 0x1)) { - if (this.validSpot(cx, cy)) { - coords.push([cx, cy]); + if (Pather.checkSpot(cx, cy, 0x1, false)) { + coords.push({x: cx, y: cy}); } } //print("ÿc9potential spots: ÿc2" + coords.length); if (coords.length > 0) { - coords.sort(Sort.points); // sort angles by final spot distance + coords.sort(Sort.units); - for (i = 0; i < coords.length; i += 1) { // sorted angles are coords[i][2] - if (!CollMap.checkColl(unit, {x: coords[i][0], y: coords[i][1]}, coll)) { + for (i = 0; i < coords.length; i += 1) { + // Valid position found + 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)); - CollMap.reset(); - return (walk ? Pather.walkTo(coords[i][0], coords[i][1]) : Pather.moveTo(coords[i][0], coords[i][1])); + switch (walk) { + case 1: + Pather.walkTo(coords[i].x, coords[i].y, 2); + + 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; } } } } - CollMap.reset(); - //print("optimal pos fail."); + if (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 ac73c2168..d1c2176e3 100644 --- a/d2bs/kolbot/libs/common/Attacks/Amazon.js +++ b/d2bs/kolbot/libs/common/Attacks/Amazon.js @@ -5,112 +5,118 @@ */ var ClassAttack = { - skillRange: [], - skillHand: [], - skillElement: [], bowCheck: false, - - init: function () { - var 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] = 15; - break; - default: // Every other skill - this.skillRange[i] = 20; - break; - } - } - - this.bowCheck = Attack.usingBow(); - }, + lightFuryTick: 0, 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(States.SKILLDELAY) || !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; + index = ((unit.spectype & 0x7) || unit.type === UnitType.Player) ? 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]) && ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard].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]) && ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard].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); - } - delay(300); + // Low mana timed skill + if (Config.LowManaSkill[0] > -1 && Skill.getManaCost(timedSkill) > me.mp && Attack.checkResist(unit, Config.LowManaSkill[0])) { + timedSkill = Config.LowManaSkill[0]; + } - return 3; + // 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 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; + } + + break; + } + + // Couldn't attack + return false; }, afterAttack: function () { + var needRepair; + + Misc.unShift(); Precast.doPrecast(false); - if (Town.needRepair()) { // Repair check, mainly to restock arrows + needRepair = Town.needRepair(); + + if (needRepair && needRepair.length > 0) { // Repair check, mainly to restock arrows Town.visitTown(); } + + this.lightFuryTick = 0; }, - doCast: function (unit, index) { - var i; + // Returns: 0 - fail, 1 - success, 2 - no valid attack skills + doCast: function (unit, timedSkill, untimedSkill) { + var i, walk; - // arrow/bolt check + // No valid skills can be found + if (timedSkill < 0 && untimedSkill < 0) { + return 2; + } + + // Arrow/bolt check if (this.bowCheck) { switch (this.bowCheck) { case "bow": @@ -128,36 +134,80 @@ var ClassAttack = { } } - if (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[index])) { - if (Math.round(getDistance(me, unit)) > this.skillRange[index] || checkCollision(me, unit, 0x4)) { - // walk short distances instead of tele for melee attacks - if (!Attack.getIntoPosition(unit, this.skillRange[index], 0x4, this.skillRange[index] < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1))) { + if (timedSkill > -1 && (!me.getState(States.SKILLDELAY) || !Skill.isTimed(timedSkill))) { + switch (timedSkill) { + case Skills.Amazon.Lightning_Fury: + 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 (!unit.dead && Skill.cast(timedSkill, Skill.getHand(timedSkill), unit)) { + this.lightFuryTick = getTickCount(); + } + + return 1; + } + + break; + default: + if (Skill.getRange(timedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { return 0; } - } - return Skill.cast(Config.AttackSkill[index], this.skillHand[index], unit); + 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 (!unit.dead) { + Skill.cast(timedSkill, Skill.getHand(timedSkill), unit); + } + + return 1; + } } - if (Config.AttackSkill[index + 1] > -1) { - if (Math.round(getDistance(me, unit)) > this.skillRange[index + 1] || checkCollision(me, unit, 0x4)) { - // walk short distances instead of tele for melee attacks - if (!Attack.getIntoPosition(unit, this.skillRange[index + 1], 0x4, this.skillRange[index + 1] < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1))) { + 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, Skill.getRange(untimedSkill), 0x4, walk)) { return 0; } } - return Skill.cast(Config.AttackSkill[index + 1], this.skillHand[index + 1], 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)) { + if (!me.getState(States.SKILLDELAY)) { break; } + + delay(40); } - return false; + // Wait for Lightning Fury timeout + while (this.lightFuryTick && getTickCount() - this.lightFuryTick < Config.LightningFuryDelay * 1000) { + delay(40); + } + + 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 80c5637ec..7c16b6581 100644 --- a/d2bs/kolbot/libs/common/Attacks/Assassin.js +++ b/d2bs/kolbot/libs/common/Attacks/Assassin.js @@ -5,79 +5,37 @@ */ var ClassAttack = { - skillRange: [], - skillHand: [], - skillElement: [], lastTrapPos: {}, - - init: function () { - var 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; - break; - default: // Every other skill - this.skillRange[i] = 20; - break; - } - } - }, + trapRange: 20, 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(States.SKILLDELAY) || !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; + index = ((unit.spectype & 0x7) || unit.type === UnitType.Player) ? 1 : 3; checkTraps = this.checkTraps(unit); if (checkTraps) { - if (Math.round(getDistance(me, unit)) > 20 || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, 20, 0x4)) { - return 1; + 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 false; } } @@ -85,85 +43,151 @@ var ClassAttack = { } // Cloak of Shadows - can't be cast again until previous one runs out and next to useless if cast in precast sequence (won't blind anyone) - if (Config.UseCloakofShadows && me.getSkill(264, 1) && getDistance(me, unit) < 20 && !me.getState(121) && !me.getState(153)) { - Skill.cast(264, 0); + if (Config.UseCloakofShadows && me.getSkill(Skills.Assassin.Cloak_of_Shadows, 1) && getDistance(me, unit) < 20 && !me.getState(States.SKILLDELAY) && !me.getState(States.CLOAK_OF_SHADOWS)) { + Skill.cast(Skills.Assassin.Cloak_of_Shadows, 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]) && ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard].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]) && ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard].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 () { + Misc.unShift(); Precast.doPrecast(false); }, - doCast: function (unit, index) { - var i; + // Returns: 0 - fail, 1 - success, 2 - no valid attack skills + doCast: function (unit, timedSkill, untimedSkill) { + var i, walk; - if (unit.mode === 0 || unit.mode === 12) { - return true; + // No valid skills can be found + if (timedSkill < 0 && untimedSkill < 0) { + return 2; } - if (Config.AttackSkill[index] === 151) { - if (Math.round(getDistance(me, unit)) > this.skillRange[index] || checkCollision(me, unit, 0x1)) { - if (!Attack.getIntoPosition(unit, this.skillRange[index], 0x1)) { - return 0; + if (timedSkill > -1 && (!me.getState(States.SKILLDELAY) || !Skill.isTimed(timedSkill))) { + switch (timedSkill) { + case Skills.Barbarian.Whirlwind: // Whirlwind + if (Math.round(getDistance(me, unit)) > Skill.getRange(timedSkill) || checkCollision(me, unit, 0x1)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(timedSkill), 0x1)) { + return 0; + } } - } - return this.whirlwind(unit, index); - } + if (!unit.dead) { + this.whirlwind(unit); + } - if (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[index])) { - if (Math.round(getDistance(me, unit)) > this.skillRange[index] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[index], 0x4)) { + return 1; + default: + if (Skill.getRange(timedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { return 0; } - } - return Skill.cast(Config.AttackSkill[index], this.skillHand[index], unit); + 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 (!unit.dead) { + Skill.cast(timedSkill, Skill.getHand(timedSkill), unit); + } + + return 1; + } } - if (Config.AttackSkill[index + 1] > -1) { - if (Math.round(getDistance(me, unit)) > this.skillRange[index + 1] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[index + 1], 0x4)) { + 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, Skill.getRange(untimedSkill), 0x4, walk)) { return 0; } } - return Skill.cast(Config.AttackSkill[index + 1], this.skillHand[index + 1], 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)) { + if (!me.getState(States.SKILLDELAY)) { break; } + + delay(40); } - return false; + return 1; }, checkTraps: function (unit) { @@ -187,58 +211,61 @@ var ClassAttack = { for (i = -1; i <= 1; i += 1) { for (j = -1; j <= 1; j += 1) { - if (Math.abs(i) !== Math.abs(j)) { // used for X formation - continue; - } - - // unit can be an object with x, y props too, that's why having "mode" prop is checked - if (traps >= amount || (unit.hasOwnProperty("mode") && (unit.mode === 0 || unit.mode === 12))) { - return true; - } - - if (unit.hasOwnProperty("classid") && [211, 242, 243, 544].indexOf(unit.classid) > -1) { // Duriel, Mephisto, Diablo, Baal - if (traps >= Config.BossTraps.length) { + if (Math.abs(i) === Math.abs(j)) { // used for X formation + // unit can be an object with x, y props too, that's why having "mode" prop is checked + if (traps >= amount || (unit.hasOwnProperty("mode") && (unit.mode === NPCModes.death || unit.mode === NPCModes.dead))) { return true; } - Skill.cast(Config.BossTraps[traps], 0, unit.x + i, unit.y + j); - } else { - if (traps >= Config.Traps.length) { - return true; + if ((unit.hasOwnProperty("classid") && [UnitClassID.duriel, UnitClassID.mephisto, UnitClassID.diablo, UnitClassID.baalcrab].indexOf(unit.classid) > -1) || (unit.hasOwnProperty("type") && unit.type === UnitType.Player)) { // Duriel, Mephisto, Diablo, Baal, other players + if (traps >= Config.BossTraps.length) { + return true; + } + + Skill.cast(Config.BossTraps[traps], 0, unit.x + i, unit.y + j); + } else { + if (traps >= Config.Traps.length) { + return true; + } + + Skill.cast(Config.Traps[traps], 0, unit.x + i, unit.y + j); } - Skill.cast(Config.Traps[traps], 0, unit.x + i, unit.y + j); + traps += 1; } - - traps += 1; } } return true; }, - whirlwind: function (unit, index) { - var i, j, coords, angle, - //angles = [180, 45, -45, 90, -90]; // Angle offsets - angles = [120, -120, 180, 45, -45, 90, -90]; // Angle offsets + whirlwind: function (unit) { + if (!Attack.checkMonster(unit)) { + return true; + } + + 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); -MainLoop: for (i = 0; i < angles.length; i += 1) { // get a better spot - for (j = 0; j < 5; j += 1) { - coords = [Math.round((Math.cos((angle + angles[i]) * Math.PI / 180)) * j + unit.x), Math.round((Math.sin((angle + angles[i]) * Math.PI / 180)) * j + unit.y)]; + 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.getColl(coords[0], coords[1]) & 0x1) { - continue MainLoop; - } + if (!CollMap.checkColl(me, {x: coords[0], y: coords[1]}, 0x1, 1)) { + return Skill.cast(Skills.Barbarian.Whirlwind, 0, coords[0], coords[1]); } + } - if (getDistance(me, coords[0], coords[1]) >= 3) { - return Skill.cast(Config.AttackSkill[index], this.skillHand[index], coords[0], coords[1]); - } + if (!Attack.validSpot(unit.x, unit.y)) { + return false; } - return false; + return Skill.cast(Skills.Barbarian.Whirlwind, 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 4fab5d577..52ae5739e 100644 --- a/d2bs/kolbot/libs/common/Attacks/Barbarian.js +++ b/d2bs/kolbot/libs/common/Attacks/Barbarian.js @@ -5,167 +5,146 @@ */ var ClassAttack = { - skillRange: [], - skillHand: [], - skillElement: [], - - init: function () { - var 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 : 2; - 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] = 2; - 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] = 5; - break; - case 151: // Whirlwind - this.skillRange[i] = 10; - break; - case 132: // Leap - this.skillRange[i] = 10; // TODO: Calculation - 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(States.SKILLDELAY) || !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 : 2; + index = ((unit.spectype & 0x7) || unit.type === UnitType.Player) ? 1 : 3; - if (Attack.checkResist(unit, this.skillElement[index])) { - if (Config.Werewolf && !me.getState(139)) { - Misc.shapeShift(0); - } + if (Attack.getCustomAttack(unit)) { + attackSkill = Attack.getCustomAttack(unit)[0]; + } else { + attackSkill = Config.AttackSkill[index]; + } - switch (this.doCast(unit, index)) { - case 0: // total fail - return 1; - case false: // fail to cast - return 2; - } + if (!Attack.checkResist(unit, attackSkill)) { + attackSkill = -1; - return 3; + if (Config.AttackSkill[index + 1] > -1 && Attack.checkResist(unit, Config.AttackSkill[index + 1])) { + attackSkill = Config.AttackSkill[index + 1]; + } } - if (Config.AttackSkill[3] > -1 && Attack.checkResist(unit, this.skillElement[3])) { - switch (this.doCast(unit, 3)) { - case 0: // total fail - return 1; - case false: // fail to cast - return 2; - } + // Low mana skill + if (Skill.getManaCost(attackSkill) > me.mp && Config.LowManaSkill[0] > -1 && Attack.checkResist(unit, Config.LowManaSkill[0])) { + attackSkill = Config.LowManaSkill[0]; + } - return 3; + switch (this.doCast(unit, attackSkill)) { + case 0: // Fail + break; + case 1: // Success + return true; + case 2: // Telestomp with barbs is pointless + break; } - return 1; + // Couldn't attack + return false; }, - afterAttack: function () { + afterAttack: function (pickit) { + var needRepair; + + Misc.unShift(); Precast.doPrecast(false); - this.findItem(me.area === 83 ? 60 : 20); - if (me.getState(139)) { - Misc.unShift(); + needRepair = Town.needRepair(); + + if (needRepair && needRepair.length > 0) { // Repair check + Town.visitTown(); + } + + if (pickit) { + this.findItem(me.area === Areas.Act3.Travincal ? 60 : 20); } }, - doCast: function (unit, index) { - if (Config.AttackSkill[index] === 151) { - if (Math.round(getDistance(me, unit)) > this.skillRange[index] || checkCollision(me, unit, 0x1)) { - if (!Attack.getIntoPosition(unit, this.skillRange[index], 0x1)) { + doCast: function (unit, attackSkill) { + var walk; + + if (attackSkill < 0) { + return 2; + } + + switch (attackSkill) { + case Skills.Barbarian.Whirlwind: + if (Math.ceil(getDistance(me, unit)) > Skill.getRange(attackSkill) || checkCollision(me, unit, 0x1)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(attackSkill), 0x1, 2)) { return 0; } } - if (!this.whirlwind(unit, index)) { - if (Config.AttackSkill[4] > 0) { - index = 4; - } else { - return false; - } - } else { - return true; + if (!unit.dead) { + this.whirlwind(unit); } - } - if (Math.round(getDistance(me, unit)) > this.skillRange[index] || checkCollision(me, unit, 0x4)) { - // walk short distances instead of tele for melee attacks - if (!Attack.getIntoPosition(unit, this.skillRange[index], 0x4, me.getState(139) || (this.skillRange[index] < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x7)))) { + return 1; + default: + if (Skill.getRange(attackSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { return 0; } - } - return Skill.cast(Config.AttackSkill[index], this.skillHand[index], unit); + 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, Skill.getRange(attackSkill), 0x4, walk)) { + return 0; + } + } + + if (!unit.dead) { + Skill.cast(attackSkill, Skill.getHand(attackSkill), unit); + } + + return 1; + } }, - whirlwind: function (unit, index) { - if (me.mp < 30) { - return false; + whirlwind: function (unit) { + if (!Attack.checkMonster(unit)) { + return true; } var i, coords, angle, - //angles = [180, 45, -45, 90, -90]; // Angle offsets - angles = [120, -120, 180, 45, -45, 90, -90]; // Angle offsets + 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 = 0; angle = Math.round(Math.atan2(me.y - unit.y, me.x - unit.x) * 180 / Math.PI); -MainLoop: for (i = 0; i < angles.length; i += 1) { // get a better spot - coords = [Math.round((Math.cos((angle + angles[i]) * Math.PI / 180)) * 3 + unit.x), Math.round((Math.sin((angle + angles[i]) * Math.PI / 180)) * 3 + unit.y)]; - - if (!CollMap.checkColl(unit, {x: coords[0], y: coords[1]})) { - if (getDistance(me, coords[0], coords[1]) >= 3) { - //me.runwalk = me.gametype; + 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)]; - 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, Skill.getHand(151), coords[0], coords[1]); } } - return false; + if (!Attack.validSpot(unit.x, unit.y)) { + return false; + } + + return Skill.cast(Skills.Barbarian.Whirlwind, Skill.getHand(Skills.Barbarian.Whirlwind), me.x, me.y); }, checkCloseMonsters: function (range) { @@ -175,9 +154,9 @@ MainLoop: if (monster) { do { - if (Attack.checkMonster(monster) && getDistance(me, monster) <= range && !checkCollision(me, monster, 0x4) && - // Account for attackable monsters - (Attack.checkResist(monster, this.skillElement[(monster.spectype & 0xF) ? 1 : 2]) || (Config.AttackSkill[3] > -1 && Attack.checkResist(monster, this.skillElement[3])))) { + if (getDistance(me, monster) <= range && Attack.checkMonster(monster) && !checkCollision(me, monster, 0x4) && + (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()); @@ -187,11 +166,11 @@ MainLoop: }, findItem: function (range) { - if (!Config.FindItem || !me.getSkill(142, 1)) { + if (!Config.FindItem || !me.getSkill(Skills.Barbarian.Find_Item, 1)) { return false; } - var i, j, tick, corpse, orgX, orgY, + var i, j, tick, corpse, orgX, orgY, retry, corpseList = []; orgX = me.x; @@ -199,23 +178,25 @@ MainLoop: MainLoop: for (i = 0; i < 3; i += 1) { - corpse = getUnit(1, -1, 12); + corpse = getUnit(UnitType.NPC); if (corpse) { do { - if (getDistance(corpse, orgX, orgY) <= range && this.checkCorpse(corpse)) { + if ((corpse.mode === NPCModes.death || corpse.mode === NPCModes.dead) && getDistance(corpse, orgX, orgY) <= range && this.checkCorpse(corpse)) { corpseList.push(copyUnit(corpse)); } } while (corpse.getNext()); } while (corpseList.length > 0) { - if (this.checkCloseMonsters(15)) { + if (this.checkCloseMonsters(5)) { if (Config.FindItemSwitch) { Precast.weaponSwitch(Math.abs(Config.FindItemSwitch - 1)); } - Attack.clear(15); + Attack.clear(10, false, false, false, false); + + retry = true; break MainLoop; } @@ -225,22 +206,24 @@ 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); } if (Config.FindItemSwitch) { - Precast.weaponSwitch(Config.FindItemSwitch - 1); + Precast.weaponSwitch(Config.FindItemSwitch); } CorpseLoop: for (j = 0; j < 3; j += 1) { - Skill.cast(142, 0, corpse); + Skill.cast(142, 3, corpse); tick = getTickCount(); while (getTickCount() - tick < 1000) { - if (corpse.getState(118)) { + if (corpse.getState(States.CORPSE_NOSELECT)) { + Pickit.fastPick(); + break CorpseLoop; } @@ -251,6 +234,10 @@ CorpseLoop: } } + if (retry) { + return this.findItem(me.area === Areas.Act3.Travincal ? 60 : 20); + } + if (Config.FindItemSwitch) { Precast.weaponSwitch(Math.abs(Config.FindItemSwitch - 1)); } @@ -261,25 +248,25 @@ CorpseLoop: }, checkCorpse: function (unit) { - if (unit.mode !== 12) { + if (unit.mode !== NPCModes.death && unit.mode !== NPCModes.dead) { return false; } - if ([345, 346, 347].indexOf(unit.classid) === -1 && unit.spectype === 0) { + if ([UnitClassID.councilmember1, UnitClassID.councilmember2, UnitClassID.councilmember3].indexOf(unit.classid) === -1 && unit.spectype === 0) { return false; } - if (unit.classid <= 575 && !getBaseStat("monstats2", unit.classid, "corpseSel")) { // monstats2 doesn't contain guest monsters info. sigh.. + if (unit.classid <= UnitClassID.sk_archer6 && !getBaseStat("monstats2", unit.classid, "corpseSel")) { // monstats2 doesn't contain guest monsters info. sigh.. return false; } if (getDistance(me, unit) <= 25 && - !unit.getState(1) && // freeze - !unit.getState(96) && // revive - !unit.getState(99) && // redeemed - !unit.getState(104) && // nodraw - !unit.getState(107) && // shatter - !unit.getState(118) // noselect + !unit.getState(States.FREEZE) && // freeze + !unit.getState(States.REVIVE) && // revive + !unit.getState(States.REDEEMED) && // redeemed + !unit.getState(States.CORPSE_NODRAW) && // nodraw + !unit.getState(States.SHATTER) && // shatter + !unit.getState(States.CORPSE_NOSELECT) // noselect ) { return true; } diff --git a/d2bs/kolbot/libs/common/Attacks/Druid.js b/d2bs/kolbot/libs/common/Attacks/Druid.js index e798d7a04..2d01cae5f 100644 --- a/d2bs/kolbot/libs/common/Attacks/Druid.js +++ b/d2bs/kolbot/libs/common/Attacks/Druid.js @@ -5,158 +5,178 @@ */ var ClassAttack = { - skillRange: [], - skillHand: [], - skillElement: [], - - init: function () { - var 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; - case 232: // Feral Rage - case 233: // Maul - case 238: // Rabies - case 239: // Fire Claws - case 242: // Hunger - case 248: // Fury - this.skillRange[i] = 3; - break; - case 243: // Shock Wave - this.skillRange[i] = 8; - break; - default: // Every other skill - this.skillRange[i] = 20; - break; - } - } - }, - doAttack: function (unit, preattack) { if (Config.MercWatch && Town.needMerc()) { Town.visitTown(); } - if (me.getSkill(250, 1) && !me.getState(144)) { // Rebuff Hurricane - Skill.cast(250, 0); + if (me.getSkill(Skills.Druid.Hurricane, 1) && !me.getState(States.HURRICANE)) { // Rebuff Hurricane + Skill.cast(Skills.Druid.Hurricane, 0); } - if (me.getSkill(235, 1) && !me.getState(151)) { // Rebuff Cyclone Armor - Skill.cast(235, 0); + if (me.getSkill(Skills.Druid.Cyclone_Armor, 1) && !me.getState(States.CYCLONEARMOR)) { // Rebuff Cyclone Armor + Skill.cast(Skills.Druid.Cyclone_Armor, 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(States.SKILLDELAY) || !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; + index = ((unit.spectype & 0x7) || unit.type === UnitType.Player) ? 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]) && ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard].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]) && ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard].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]; + } + + // 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]); + } - delay(300); + return true; + } - return 3; + break; } - return 1; + // Couldn't attack + return false; }, afterAttack: function () { + Misc.unShift(); Precast.doPrecast(false); }, - doCast: function (unit, index) { - var i; + // 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; + } + + if (timedSkill > -1 && (!me.getState(States.SKILLDELAY) || !Skill.isTimed(timedSkill))) { + switch (timedSkill) { + case Skills.Druid.Tornado: // 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 (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[index])) { - if (Math.round(getDistance(me, unit)) > this.skillRange[index] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[index], 0x4)) { + return 1; + default: + 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 (!unit.dead) { + Skill.cast(timedSkill, Skill.getHand(timedSkill), unit); + } + + return 1; } + } - if (Config.AttackSkill[index] === 245) { - return Skill.cast(Config.AttackSkill[index], this.skillHand[index], unit.x + rand(-2, 2), unit.y); + if (untimedSkill > -1) { + if (Skill.getRange(untimedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { + return 0; } - return Skill.cast(Config.AttackSkill[index], this.skillHand[index], unit); - } + 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 (Config.AttackSkill[index + 1] > -1) { - if (Math.round(getDistance(me, unit)) > this.skillRange[index + 1] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[index + 1], 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(untimedSkill), 0x4, walk)) { return 0; } } - return Skill.cast(Config.AttackSkill[index + 1], this.skillHand[index + 1], 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)) { + if (!me.getState(States.SKILLDELAY)) { 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 8aa34a5b3..a2282d345 100644 --- a/d2bs/kolbot/libs/common/Attacks/Necromancer.js +++ b/d2bs/kolbot/libs/common/Attacks/Necromancer.js @@ -5,318 +5,369 @@ */ var ClassAttack = { - skillRange: [], - skillHand: [], - skillElement: [], - curseState: [], novaTick: 0, + cursesSet: false, + curseState: [], - init: function () { + initCurses: function () { var 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] = 3; - break; - default: // Every other skill - this.skillRange[i] = 20; - break; - } - } - - for (i = 0 ; i < Config.Curse.length ; i+= 1) { + for (i = 0; i < Config.Curse.length; i += 1) { switch (Config.Curse[i]) { - case 0: //nothing + case Skills.common.Attack: //nothing this.curseState[i] = 0; + break; - case 66: //amplify damage + case Skills.Necromancer.Amplify_Damage: //amplify damage this.curseState[i] = 9; + break; - case 71: //dim vision + case Skills.Necromancer.Dim_Vision: //dim vision this.curseState[i] = 23; + break; - case 72: //weaken + case Skills.Necromancer.Weaken: //weaken this.curseState[i] = 19; + break; - case 76: //iron maiden + case Skills.Necromancer.Iron_Maiden: //iron maiden this.curseState[i] = 55; + break; - case 77: //terror + case Skills.Necromancer.Terror: //terror this.curseState[i] = 56; + break; - case 81: //confuse + case Skills.Necromancer.Confuse: //confuse this.curseState[i] = 59; + break; - case 82: //life tap + case Skills.Necromancer.Life_Tap: //life tap this.curseState[i] = 58; + break; - case 86: //attract + case Skills.Necromancer.Attract: //attract this.curseState[i] = 57; + break; - case 87: //decrepify + case Skills.Necromancer.Decrepify: //decrepify this.curseState[i] = 60; + break; - case 91: //lower resist + case Skills.Necromancer.Lower_Resist: //lower resist this.curseState[i] = 61; + break; default: Config.Curse[i] = 0; print("Invalid curse id"); + 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(States.SKILLDELAY) || !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]) && ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard].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]) && ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard].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 3; + return true; + } + + break; } - return 1; + // Couldn't attack + return false; }, afterAttack: function () { + Misc.unShift(); Precast.doPrecast(false); this.raiseArmy(); this.novaTick = 0; }, - doCast: function (unit, index) { - var i; + // Returns: 0 - fail, 1 - success, 2 - no valid attack skills + doCast: function (unit, timedSkill, untimedSkill) { + var i, walk; - if (Config.AttackSkill[index] === 92) { - if (!this.novaTick || getTickCount() - this.novaTick > Config.PoisonNovaDelay) { - if (Math.round(getDistance(me, unit)) > this.skillRange[index] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[index], 0x4)) { - return 0; + // No valid skills can be found + if (timedSkill < 0 && untimedSkill < 0) { + return 2; + } + + // 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(States.SKILLDELAY) || !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(); } } - if (Skill.cast(Config.AttackSkill[index], this.skillHand[index], unit)) { - this.novaTick = getTickCount(); - - return true; + 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; + } } - return false; - } - } else if (!me.getState(121) || !Skill.isTimed(Config.AttackSkill[index])) { - if (Math.round(getDistance(me, unit)) > this.skillRange[index] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[index], 0x4)) { + delay(300); + + break; + default: + 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 (!unit.dead) { + Skill.cast(timedSkill, Skill.getHand(timedSkill), unit); + } + + break; } + } - if (Config.AttackSkill[index] === 500) { - delay(300); - - return true; + if (untimedSkill > -1) { + if (Skill.getRange(untimedSkill) < 4 && !Attack.validSpot(unit.x, unit.y)) { + return 0; } - return Skill.cast(Config.AttackSkill[index], this.skillHand[index], unit); - } + 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 (Config.AttackSkill[index + 1] > -1) { - if (Math.round(getDistance(me, unit)) > this.skillRange[index + 1] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[index + 1], 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(untimedSkill), 0x4, walk)) { return 0; } } - return Skill.cast(Config.AttackSkill[index + 1], this.skillHand[index + 1], 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)) { + if (!me.getState(States.SKILLDELAY)) { break; } + + delay(40); } - while (this.novaTick && getTickCount() - this.novaTick < Config.PoisonNovaDelay) { + // 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; } - if (unit.getState(57)) { // attract can't be overridden + if (unit.getState(States.ATTRACT)) { // attract can't be overridden return false; } switch (unit.classid) { - case 206: // Foul Crow Nest - case 258: // Water Watcher - case 261: // Water Watcher - case 266: // Flavie - case 528: // Evil Demon Hut + case UnitClassID.crownest1: // Foul Crow Nest + case UnitClassID.tentacle1: // Water Watcher + case UnitClassID.tentaclehead1: // Water Watcher + case UnitClassID.navi: // Flavie + case UnitClassID.evilhut: // Evil Demon Hut return false; } return true; }, - raiseArmy: function () { + raiseArmy: function (range) { var i, tick, count, corpse, corpseList, skill, maxSkeletons, maxMages, maxRevives; + if (!range) { + range = 25; + } + if (Config.Skeletons === "max") { - skill = me.getSkill(70, 1); + skill = me.getSkill(Skills.Necromancer.Raise_Skeleton, 1); maxSkeletons = skill < 4 ? skill : (Math.floor(skill / 3) + 2); } else { maxSkeletons = Config.Skeletons; } if (Config.SkeletonMages === "max") { - skill = me.getSkill(80, 1); + skill = me.getSkill(Skills.Necromancer.Raise_Skeletal_Mage, 1); maxMages = skill < 4 ? skill : (Math.floor(skill / 3) + 2); } else { maxMages = Config.SkeletonMages; } if (Config.Revives === "max") { - skill = me.getSkill(95, 1); + skill = me.getSkill(Skills.Necromancer.Revive, 1); maxRevives = skill; } else { maxRevives = Config.Revives; } for (i = 0; i < 3; i += 1) { - corpse = getUnit(1, -1, 12); + corpse = getUnit(UnitType.NPC, -1, NPCModes.dead); corpseList = []; if (corpse) { do { - if (getDistance(me, corpse) <= 25 && this.checkCorpse(corpse)) { // within casting distance + if (getDistance(me, corpse) <= range && this.checkCorpse(corpse)) { // within casting distance corpseList.push(copyUnit(corpse)); } } while (corpse.getNext()); } - MainLoop : while (corpseList.length > 0) { +MainLoop: + while (corpseList.length > 0) { corpse = corpseList.shift(); if (me.getMinionCount(4) < maxSkeletons) { - if (!Skill.cast(70, 0, corpse)) { + if (!Skill.cast(Skills.Necromancer.Raise_Skeleton, 0, corpse)) { return false; } @@ -331,7 +382,7 @@ var ClassAttack = { delay(10); } } else if (me.getMinionCount(5) < maxMages) { - if (!Skill.cast(80, 0, corpse)) { + if (!Skill.cast(Skills.Necromancer.Raise_Skeletal_Mage, 0, corpse)) { return false; } @@ -346,25 +397,23 @@ var ClassAttack = { delay(10); } } else if (me.getMinionCount(6) < maxRevives) { - if (!this.checkCorpse(corpse, true)) { - continue MainLoop; - } + if (this.checkCorpse(corpse, true)) { + print("Reviving " + corpse.name); - print("Reviving " + corpse.name); + if (!Skill.cast(Skills.Necromancer.Revive, 0, corpse)) { + return false; + } - if (!Skill.cast(95, 0, corpse)) { - return false; - } + count = me.getMinionCount(6); + tick = getTickCount(); - count = me.getMinionCount(6); - tick = getTickCount(); + while (getTickCount() - tick < 200) { + if (me.getMinionCount(6) > count) { + break; + } - while (getTickCount() - tick < 200) { - if (me.getMinionCount(6) > count) { - break; + delay(10); } - - delay(10); } } else { return true; @@ -376,52 +425,96 @@ var ClassAttack = { }, explodeCorpses: function (unit) { - if (Config.ExplodeCorpses === 0 || unit.mode === 0 || unit.mode === 12) { + if (Config.ExplodeCorpses === 0 || unit.mode === NPCModes.death || unit.mode === NPCModes.dead) { return false; } - var corpseList = [], + var i, + corpseList = [], range = Math.floor((me.getSkill(Config.ExplodeCorpses, 1) + 7) / 3), - corpse = getUnit(1, -1, 12); + corpse = getUnit(UnitType.NPC, -1, NPCModes.dead); if (corpse) { do { if (getDistance(unit, corpse) <= range && this.checkCorpse(corpse)) { corpseList.push(copyUnit(corpse)); + } + } while (corpse.getNext()); + + //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 (corpseList.length >= 2) { // Explode 2 corpses per cycle, so we can leave some for summoning + 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(UnitType.NPC, -1, NPCModes.dead); - 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) { - if (unit.mode !== 12) { + if (unit.mode !== NPCModes.dead) { return false; } - if (arguments.length < 2) { + if (revive === undefined) { revive = false; } var baseId = getBaseStat("monstats", unit.classid, "baseid"), - badList = [312, 571]; + badList = [UnitClassID.doomknight3, UnitClassID.baalminion1]; - if (revive && ((unit.spectype & 0x7) || badList.indexOf(baseId) > -1 || Config.ReviveUnstackable && getBaseStat("monstats2", baseId, "sizex") === 3)) { + if (revive && ((unit.spectype & 0x7) || badList.indexOf(baseId) > -1 || (Config.ReviveUnstackable && getBaseStat("monstats2", baseId, "sizex") === 3))) { return false; } @@ -429,14 +522,14 @@ var ClassAttack = { return false; } - if (getDistance(me, unit) <= 25 && !checkCollision(me, unit, 0x4) && - !unit.getState(1) && // freeze - !unit.getState(96) && // revive - !unit.getState(99) && // redeemed - !unit.getState(104) && // nodraw - !unit.getState(107) && // shatter - !unit.getState(118) // noselect - ) { + if (getDistance(me, unit) <= 25 && !checkCollision(me, unit, 0x4) && + !unit.getState(States.FREEZE) && // freeze + !unit.getState(States.REVIVE) && // revive + !unit.getState(States.REDEEMED) && // redeemed + !unit.getState(States.CORPSE_NODRAW) && // nodraw + !unit.getState(States.SHATTER) && // shatter + !unit.getState(States.CORPSE_NOSELECT) // noselect + ) { return true; } diff --git a/d2bs/kolbot/libs/common/Attacks/Paladin.js b/d2bs/kolbot/libs/common/Attacks/Paladin.js index 8b22ae035..08be55dd5 100644 --- a/d2bs/kolbot/libs/common/Attacks/Paladin.js +++ b/d2bs/kolbot/libs/common/Attacks/Paladin.js @@ -5,175 +5,229 @@ */ var ClassAttack = { - skillRange: [], - skillHand: [], - skillElement: [], - - init: function () { - var 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 112: // Blessed Hammer - case 116: // Conversion - 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 (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(States.SKILLDELAY) || !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; + index = ((unit.spectype & 0x7) || unit.type === UnitType.Player) ? 1 : 3; - if (Attack.checkResist(unit, this.skillElement[index])) { - if (this.skillRange[index] < 4 && checkCollision(me, unit, 0x1) && (getCollision(unit.area, unit.x, unit.y) & 0x1)) { - 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 () { + Misc.unShift(); Precast.doPrecast(false); - if (Config.Redemption instanceof Array && (me.hp * 100 / me.hpmax < Config.Redemption[0] || me.mp * 100 / me.mpmax < Config.Redemption[1]) && Skill.setSkill(124, 0)) { + if (Config.Redemption instanceof Array && (me.hp * 100 / me.hpmax < Config.Redemption[0] || me.mp * 100 / me.mpmax < Config.Redemption[1]) && Skill.setSkill(Skills.Paladin.Redemption, 0)) { delay(1500); } }, - doCast: function (unit, index) { - var i; + doCast: function (unit, attackSkill, aura) { + var i, walk; - if (Config.AttackSkill[index] === 112) { - if (unit.classid === 691) { - Attack.getIntoPosition(unit, 15, 0x4); + if (attackSkill < 0) { + return false; + } + + switch (attackSkill) { + case Skills.Paladin.Blessed_Hammer: + if (unit.classid === UnitClassID.bonefetish7 && Config.AvoidDolls) { + this.dollAvoid(unit); - if (Config.AttackSkill[index + 1] > -1) { - Skill.setSkill(Config.AttackSkill[index + 1], 0); + if (aura > -1) { + Skill.setSkill(aura, 0); } - return Skill.cast(Config.AttackSkill[index], this.skillHand[index], unit); + Skill.cast(attackSkill, Skill.getHand(attackSkill), unit); + + return 1; } - if (!this.checkHammerPosition(unit)) { - this.getHammerPosition(unit); + if (!this.getHammerPosition(unit)) { + //print("Can't get to " + unit.name); - if (getDistance(me, unit) > 6) { // increase pvp aggressiveness - return false; + // Fallback to secondary skill if it exists + if (Config.AttackSkill[5] > -1 && Config.AttackSkill[5] !== Skills.Paladin.Blessed_Hammer && Attack.checkResist(unit, Config.AttackSkill[5])) { + return this.doCast(unit, Config.AttackSkill[5], Config.AttackSkill[6]); } + + return 0; + } + + if (getDistance(me, unit) > 9 || unit.dead) { + //print(getDistance(me, unit)); + + return 1; } - if (Config.AttackSkill[index + 1] > -1) { - Skill.setSkill(Config.AttackSkill[index + 1], 0); + if (aura > -1) { + Skill.setSkill(aura, 0); } for (i = 0; i < 3; i += 1) { - Skill.cast(Config.AttackSkill[index], this.skillHand[index], unit); + Skill.cast(attackSkill, Skill.getHand(attackSkill), unit); - if (!Attack.checkMonster(unit) || getDistance(me, unit) > 5) { - return true; + if (!Attack.checkMonster(unit) || getDistance(me, unit) > 9 || unit.type === UnitType.Player) { + break; + } + } + + return 1; + case Skills.Paladin.Holy_Bolt: + if (getDistance(me, unit) > Skill.getRange(attackSkill) + 3 || CollMap.checkColl(me, unit, 0x4)) { + if (!Attack.getIntoPosition(unit, Skill.getRange(attackSkill), 0x4)) { + return 0; } } - return true; - } else if (Config.AttackSkill[index] === 101) { CollMap.reset(); - if (Math.round(getDistance(me, unit)) > this.skillRange[index] || CollMap.checkColl(me, unit, 0x2004)) { - if (!Attack.getIntoPosition(unit, this.skillRange[index], 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 (getDistance(me, unit) > this.skillRange[index] || checkCollision(me, unit, 0x4)) { - // walk short distances instead of tele for melee attacks - if (!Attack.getIntoPosition(unit, this.skillRange[index], 0x4, this.skillRange[index] < 4 && getDistance(me, unit) < 10 && !checkCollision(me, unit, 0x1))) { + + if (!unit.dead) { + if (aura > -1) { + Skill.setSkill(aura, 0); + } + + Skill.cast(attackSkill, Skill.getHand(attackSkill), unit); + } + + return 1; + case Skills.Paladin.Fist_of_the_Heavens: // FoH + if (!me.getState(States.SKILLDELAY)) { + 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 !== Skills.Paladin.Smite && 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[index + 1] > -1) { - Skill.setSkill(Config.AttackSkill[index + 1], 0); + for (i = 0; i < 25; i += 1) { + if (!me.getState(States.SKILLDELAY)) { + break; + } + + delay(40); } - return Skill.cast(Config.AttackSkill[index], this.skillHand[index], unit); + return 1; }, - checkHammerPosition: function (unit) { + dollAvoid: function (unit) { var i, - x = unit.x, - y = unit.y, - positions = [[x + 1, y + 1], [x - 1, y - 1], [x + 2, y]]; + positions = [[10, 10], [-10, 10], [10, -10], [-10, -10]]; for (i = 0; i < positions.length; i += 1) { - if (getDistance(me, positions[i][0], positions[i][1]) < 2) { - return true; + if (Attack.validSpot(unit.x + positions[i][0], unit.y + positions[i][1])) { + return Pather.moveTo(unit.x + positions[i][0], unit.y + positions[i][1]); } } @@ -181,16 +235,48 @@ var ClassAttack = { }, getHammerPosition: function (unit) { - var i, - x = unit.x, - y = unit.y, - positions = [[x + 1, y + 1], [x - 1, y - 1], [x + 2, y]]; + var i, x, y, positions, check, + baseId = getBaseStat("monstats", unit.classid, "baseid"), + size = getBaseStat("monstats2", baseId, "sizex"); + + // in case base stat returns something outrageous + if (typeof size !== "number" || size < 1 || size > 3) { + size = 3; + } + + switch (unit.type) { + case UnitType.Player: // Player + x = unit.x; + y = unit.y; + positions = [[x + 2, y], [x + 2, y + 1]]; + + break; + case UnitType.NPC: // Monster + x = (unit.mode === NPCModes.walk || unit.mode === NPCModes.run) && getDistance(me, unit) < 10 && getDistance(me, unit.targetx, unit.targety) > 5 ? unit.targetx : unit.x; + y = (unit.mode === NPCModes.walk || unit.mode === NPCModes.run) && getDistance(me, unit) < 10 && getDistance(me, unit.targetx, unit.targety) > 5 ? unit.targety : unit.y; + 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 + 2, y + 2]); + } + + break; + } 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]); + if (getDistance(me, positions[i][0], positions[i][1]) < 1) { + return true; + } + } + + for (i = 0; i < positions.length; 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; } } @@ -200,20 +286,19 @@ var ClassAttack = { }, reposition: function (x, y) { - while (!me.idle) { - delay(40); - } + var i; - if (getDistance(me, x, y) > 1) { - if (me.gametype === 1) { - return Pather.moveTo(x, y, 1); + if (Math.round(getDistance(me, x, y) > 0)) { + if (Pather.teleport && !me.inTown && me.getStat(Stats.item_nonclassskill, Skills.Sorceress.Teleport)) { + if (getDistance(me, x, y) > 40) { + Pather.moveTo(x, y); + } else { + Pather.teleportTo(x, y, 3); + } + } else { + Misc.click(0, 0, x, y); + delay(200); } - - me.move(x, y); - } - - while (!me.idle) { - delay(40); } return true; diff --git a/d2bs/kolbot/libs/common/Attacks/Sorceress.js b/d2bs/kolbot/libs/common/Attacks/Sorceress.js index db7f3b3cf..2510bfe12 100644 --- a/d2bs/kolbot/libs/common/Attacks/Sorceress.js +++ b/d2bs/kolbot/libs/common/Attacks/Sorceress.js @@ -5,166 +5,198 @@ */ var ClassAttack = { - skillRange: [], - skillHand: [], - skillElement: [], - - init: function () { - var 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 - this.skillRange[i] = Math.floor((me.getSkill(42, 1) + 4) * 2 / 3); - 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; - 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 (Math.round(getDistance(me, unit)) > this.skillRange[0] || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, this.skillRange[0], 0x4)) { - return 1; + if (!me.getState(States.ENERGYSHIELD) && me.getSkill(Skills.Sorceress.Energy_Shield, 1)) { + Skill.cast(Skills.Sorceress.Energy_Shield, 0); + } + + if (preattack && Config.AttackSkill[0] > 0 && Attack.checkResist(unit, Config.AttackSkill[0]) && (!me.getState(States.SKILLDELAY) || !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) && Math.round(unit.hp * 100 / unit.hpmax) > Config.CastStatic && Attack.checkResist(unit, "lightning") && Config.StaticList.indexOf(unit.name) > -1) { - staticRange = Math.floor((me.getSkill(42, 1) + 4) * 2 / 3); - - if (getDistance(me, unit) > staticRange || checkCollision(me, unit, 0x4)) { - if (!Attack.getIntoPosition(unit, staticRange, 0x4)) { - return 1; + if (Config.CastStatic < 100 && me.getSkill(Skills.Sorceress.Static_Field, 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(Skills.Sorceress.Static_Field, 1) + 4) * 2 / 3); + + 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 false; + } } - } - if (!Skill.cast(42, 0)) { - return 2; + if (!Skill.cast(Skills.Sorceress.Static_Field, 0)) { + break; + } } - - return 3; } 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) && ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard].indexOf(checkSkill) === -1 || Attack.validSpot(unit.x, unit.y))) { + timedSkill = checkSkill; + } else if (Config.AttackSkill[5] > -1 && Attack.checkResist(unit, Config.AttackSkill[5]) && ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard].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) && ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard].indexOf(checkSkill) === -1 || Attack.validSpot(unit.x, unit.y))) { + untimedSkill = checkSkill; + } else if (Config.AttackSkill[6] > -1 && Attack.checkResist(unit, Config.AttackSkill[6]) && ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard].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")) { - if (getDistance(me, unit) > 5) { - 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]; + } + + 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) > 3) { + Pather.moveToUnit(unit); + } + + this.doCast(unit, Config.AttackSkill[1], Config.AttackSkill[2]); } - // Spam attacks - timedIndex = 1; - untimedIndex = Config.AttackSkill[2] > -1 ? 2 : false; - } 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; + + // No valid skills can be found + if (timedSkill < 0 && untimedSkill < 0) { + return 2; + } + + if (timedSkill > -1 && (!me.getState(States.SKILLDELAY) || !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 (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 (!Attack.getIntoPosition(unit, Skill.getRange(timedSkill), 0x4, walk)) { return 0; } } - return Skill.cast(Config.AttackSkill[timed], this.skillHand[timed], unit); + if (!unit.dead && !checkCollision(me, unit, 0x4)) { + Skill.cast(timedSkill, Skill.getHand(timedSkill), unit); + } + + return 1; } - 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 (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, 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)) { + if (!me.getState(States.SKILLDELAY)) { 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 new file mode 100644 index 000000000..10dbf3c94 --- /dev/null +++ b/d2bs/kolbot/libs/common/Attacks/Wereform.js @@ -0,0 +1,174 @@ +/** +* @filename Wereform.js +* @author kolton +* @desc Wereform attack sequence +*/ + +var ClassAttack = { + doAttack: function (unit, preattack) { + if (Config.MercWatch && Town.needMerc()) { + Town.visitTown(); + } + + 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; + } + } + + Skill.cast(Config.AttackSkill[0], Skill.getHand(Config.AttackSkill[0]), unit); + + return true; + } + + var index, checkSkill, + timedSkill = -1, + untimedSkill = -1; + + index = ((unit.spectype & 0x7) || unit.type === 0) ? 1 : 3; + + // Get timed skill + if (Attack.getCustomAttack(unit)) { + checkSkill = Attack.getCustomAttack(unit)[0]; + } else { + checkSkill = Config.AttackSkill[index]; + } + + if (Attack.checkResist(unit, checkSkill)) { + timedSkill = checkSkill; + } else if (Config.AttackSkill[5] > -1 && Attack.checkResist(unit, Config.AttackSkill[5]) && ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard].indexOf(Config.AttackSkill[5]) === -1 || Attack.validSpot(unit.x, unit.y))) { + timedSkill = Config.AttackSkill[5]; + } + + // 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]) && ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard].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; + } + + break; + } + + // Couldn't attack + return false; + }, + + afterAttack: function () { + Misc.unShift(); + Precast.doPrecast(false); + }, + + // 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; + } + + if (timedSkill > -1 && (!me.getState(States.SKILLDELAY) || !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); + } + + return 1; + } + + 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, 10, 0x4)) { + return 0; + } + } + + Misc.shapeShift(Config.Wereform); + + 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(States.SKILLDELAY)) { + break; + } + + delay(40); + } + + return 1; + } +}; \ No newline at end of file diff --git a/d2bs/kolbot/libs/common/AutoAssign.js b/d2bs/kolbot/libs/common/AutoAssign.js new file mode 100644 index 000000000..57d090c91 --- /dev/null +++ b/d2bs/kolbot/libs/common/AutoAssign.js @@ -0,0 +1,267 @@ +var answer = false, + request = false, + + AutoAssign = { + recursion: true, + Barbs: [], + Sorcs: [], + Pallys: [], + Jobs: { + Barb: "", + Sorc: "", + Pally: "", + Mine: 0 + }, + init: function () { + AutoAssign.updateNames(); //initiates all scripts + + //Do something else? What else do we need to do... + + return true; + }, + + receiveCopyData: function (mode, msg) { + switch (mode) { + case 69: // request + if (msg === me.name) { + D2Bot.shoutGlobal("bot", 70); + } + + break; + case 70: // Received answer + if (msg == "bot" && request == true) { + answer = true; + } + + break; + default: + break; + } + }, + + gameEvent: function (mode, param1, param2, name1, name2) { + switch (mode) { + case 0x00: //Left game due to time-out + AutoAssign.updateNames(name1); + + break; + case 0x02: //Joined game + AutoAssign.updateNames(); + + break; + case 0x03://left game + AutoAssign.updateNames(name1); + break; + } + delay (250); + }, + + getJobs: function () { + + var i, y, current, quitCheck, + array = [this.Barbs, this.Pallys, this.Sorcs]; + + for (i = 0; i < array.length; i++) { + current = array[i]; + + switch (i) { + case 0: + quitCheck = getParty(this.Jobs.Barb); + + if (!quitCheck) { + this.Jobs.Barb = ""; + } + + if (current.length > 0) { + this.Jobs.Barb = current[0].name; + //print ("setting leader Barb to: " + AutoAssign.Jobs.Barb); + } + break; + case 1: + quitCheck = getParty(this.Jobs.Pally); + + if (!quitCheck) { + this.Jobs.Pally = ""; + } + + if (current.length > 0) { + this.Jobs.Pally = current[0].name; + //print ("setting leader Pally to: " + AutoAssign.Jobs.Pally); + } + break; + case 2: + quitCheck = getParty(this.Jobs.Sorc); + + if (!quitCheck) { + this.Jobs.Sorc = ""; + } + + if (current.length > 0) { + this.Jobs.Sorc = current[0].name; + //print ("setting leader Sorc to: " + AutoAssign.Jobs.Sorc); + } + break; + } + + for (y = 0; y < current.length; y++) { + if (current[y].name === me.name) { + this.Jobs.Mine = y; + } + } + } + return true; + }, + + pushNames: function (name, level, classid) { + + var obj = {name : name, level : level}; + + switch (classid) { + case ClassID.Sorceress: + this.Sorcs.push(obj); + break; + case ClassID.Paladin: + this.Pallys.push(obj); + break; + case ClassID.Barbarian: + this.Barbs.push(obj); + break; + } + return true; + }, + + checkNames: function (name, type) { + var tick, i, + timeout = 1000; + + for (i = 0; i < type.length; i++) { + if (type[i].name === name) { + break; + } + } + + if (i == type.length) { + + D2Bot.shoutGlobal(name, 69); + tick = getTickCount(); + request = true; + + while (!answer) { + if (getTickCount() - tick > timeout) { + break; + } + delay (100); + } + } + + if (answer) { + answer = false; + request = false; + //print ("Char: " + name + " Came back true."); + return true; + } + + answer = false; + request = false; + + return false; + }, + + sortNames: function () { + var i, type, + arrays = [this.Barbs, this.Pallys, this.Sorcs]; + + for (i = 0; i < arrays.length; i++) { + type = arrays[i]; + + type.sort(function (a, b) { + if (a.name > b.name) + return 1; + if (a.name < b.name) + return -1; + return 0; + }); + + type.sort(function (a, b) { + return b.level - a.level; + }); + + } + return true; + }, + + removeNames: function (quitter) { + print (quitter + " has left. updating.."); + var i, y, currentClass, + arrays = [this.Barbs, this.Pallys, this.Sorcs]; + + for (i = 0; i < arrays.length; i++) { + currentClass = arrays[i]; + + for (y = 0; y < currentClass.length; y++) { + if (currentClass[y].name === quitter) { + currentClass.splice(y, 1); + } + } + } + return true; + }, + + getNames: function () { + print ("Updating names."); + + for (var i = 0; i < 3; i++) { + var party = getParty(); + + if (party) { + do { + switch (party.classid) { + case 1: + if (this.checkNames(party.name, this.Sorcs)) { + this.pushNames(party.name, party.level, party.classid); + } + + break; + case 3: + if (this.checkNames(party.name, this.Pallys)) { + this.pushNames(party.name, party.level, party.classid); + } + + break; + case 4: + if (this.checkNames(party.name, this.Barbs)) { + this.pushNames(party.name, party.level, party.classid); + } + + break; + default: + break; + } + } while (party.getNext()); + } + } + + this.sortNames(); + this.getJobs(); + + return this.Jobs; + }, + + updateNames: function (quitter) { + if (this.recursion) { + this.recursion = false; + + if (quitter) { + this.removeNames(quitter); + } + + this.getNames(); + + this.recursion = true; + } + return true; + } +} + //addEventListener("scriptmsg", AutoAssign.ScriptMsgEvent); + addEventListener('copydata', AutoAssign.receiveCopyData); + addEventListener("gameevent", AutoAssign.gameEvent); diff --git a/d2bs/kolbot/libs/common/AutoBuild.js b/d2bs/kolbot/libs/common/AutoBuild.js new file mode 100644 index 000000000..005726d2a --- /dev/null +++ b/d2bs/kolbot/libs/common/AutoBuild.js @@ -0,0 +1,123 @@ +/** +* @title : AutoBuild.js +* +* @author : alogwe +* +* @desc : This script is included when any script includes libs/common/Config.js and calls Config.init(). +* If enabled, loads a threaded helper script that will monitor changes in character level and +* upon level up detection, it will spend skill and stat points based on a configurable +* character build template file located in libs/config/Builds/*. +* +* Any skill and stat points obtained as quest rewards are currently +* invisible to this script and must be spent manually. +* +* @todo : Make this file "libs/config/Builds/README.txt" +*/ +js_strict(true); + +if (!isIncluded("common/Cubing.js")) { include("common/Cubing.js"); }; +if (!isIncluded("common/Prototypes.js")) { include("common/Prototypes.js"); }; +if (!isIncluded("common/Runewords.js")) { include("common/Runewords.js"); }; + +var AutoBuild = new function AutoBuild () { + + if (Config.AutoBuild.DebugMode) { Config.AutoBuild.Verbose = true; } + + var debug = !!Config.AutoBuild.DebugMode, + verbose = !!Config.AutoBuild.Verbose, + configUpdateLevel = 0; + + + // Apply all Update functions from the build template in order from level 1 to me.charlvl. + // By reapplying all of the changes to the Config object, we preserve + // the state of the Config file without altering the saved char config. + function applyConfigUpdates () { + if (debug) { this.print("Updating Config from level "+configUpdateLevel+" to "+me.charlvl)} + while (configUpdateLevel < me.charlvl) { + configUpdateLevel += 1; + AutoBuildTemplate[configUpdateLevel].Update.apply(Config); // TODO: Make sure this works + } + }; + + + function getBuildType () { + var build = Config.AutoBuild.Template; + if (!build) { + this.print("Config.AutoBuild.Template is either 'false', or invalid ("+build+")"); + throw new Error("Invalid build template, read libs/config/Builds/README.txt for information"); + } + return build; + }; + + + function getCurrentScript () { + return getScript(true).name.toLowerCase(); + }; + + + function getLogFilename () { + var d = new Date(); + var dateString = d.getMonth()+"_"+d.getDate()+"_"+d.getFullYear(); + return "logs/AutoBuild."+me.realm+"."+me.charname+"."+dateString+".log"; + }; + + + function getTemplateFilename () { + var classname = ["Amazon", "Sorceress", "Necromancer", "Paladin", "Barbarian", "Druid", "Assassin"][me.classid]; + var build = getBuildType(); + var template = "config/Builds/"+classname+"."+build+".js"; + return template.toLowerCase(); + }; + + + function initialize () { + var currentScript = getCurrentScript(); + var template = getTemplateFilename(); + this.print("Including build template "+template+" into "+currentScript); + if (!include(template)) { + throw new Error("Failed to include template: "+template); + } + + // Only load() helper thread from default.dbj if it isn't loaded + if (currentScript === "default.dbj" && !getScript("tools\\autobuildthread.js")) { + load("tools/autobuildthread.js"); + } + + // All threads except autobuildthread.js use this event listener + // to update their thread-local Config object + if (currentScript !== "tools\\autobuildthread.js") { + addEventListener("scriptmsg", levelUpHandler); + } + + // Resynchronize our Config object with all past changes + // made to it by AutoBuild system + applyConfigUpdates(); + }; + + + function levelUpHandler (obj) { + if (typeof obj === "object" && obj.hasOwnProperty("event") && obj["event"] === "level up") { + applyConfigUpdates(); + } + }; + + + function log (message) { FileTools.appendText(getLogFilename(), message+"\n"); }; + + + // Only print to console from autobuildthread.js, + // but log from all scripts + function myPrint () { + var args = Array.prototype.slice.call(arguments); + args.unshift("AutoBuild:"); + var result = args.join(" "); + if (verbose) { print.call(this, result); } + if (debug) { log.call(this, result); } + }; + + + this.print = myPrint; + this.initialize = initialize; + this.applyConfigUpdates = applyConfigUpdates; + +}; diff --git a/d2bs/kolbot/libs/common/CollMap.js b/d2bs/kolbot/libs/common/CollMap.js index 9bb027ca4..ee2364b78 100644 --- a/d2bs/kolbot/libs/common/CollMap.js +++ b/d2bs/kolbot/libs/common/CollMap.js @@ -8,22 +8,57 @@ var CollMap = new function () { this.rooms = []; this.maps = []; - this.addRoom = function (x, y) { - var room = getRoom(x, y); + this.getNearbyRooms = function (x, y) { + var i, room, rooms; + + room = getRoom(x, y); + + if (!room) { + return false; + } + + rooms = room.getNearby(); - if (room instanceof Room && this.coordsInRoom(x, y, room)) { - this.rooms.push(room); - this.maps.push(room.getCollision()); - } else { + if (!rooms) { return false; } + for (i = 0; i < rooms.length; i += 1) { + if (this.getRoomIndex(rooms[i].x * 5 + rooms[i].xsize / 2, rooms[i].y * 5 + rooms[i].ysize / 2, true) === undefined) { + this.addRoom(rooms[i]); + } + } + return true; }; - this.getColl = function (x, y) { + this.addRoom = function (x, y) { + var room, coll; + + room = x instanceof Room ? x : getRoom(x, y); + + // Coords are not in the returned room. + if (arguments.length === 2 && !this.coordsInRoom(x, y, room)) { + return false; + } + + if (room) { + coll = room.getCollision(); + } + + if (coll) { + this.rooms.push({x: room.x, y: room.y, xsize: room.xsize, ysize: room.ysize}); + this.maps.push(coll); + + return true; + } + + return false; + }; + + this.getColl = function (x, y, cacheOnly) { var i, j, - index = this.getRoomIndex(x, y, true); + index = this.getRoomIndex(x, y, cacheOnly); if (index === undefined) { return 5; @@ -32,14 +67,18 @@ var CollMap = new function () { j = x - this.rooms[index].x * 5; i = y - this.rooms[index].y * 5; - if (typeof (this.maps[index][i]) === "undefined" || typeof (this.maps[index][i][j]) === "undefined") { - return 5; + if (this.maps[index] !== undefined && this.maps[index][i] !== undefined && this.maps[index][i][j] !== undefined) { + return this.maps[index][i][j]; } - return this.maps[index][i][j]; + return 5; }; - this.getRoomIndex = function (x, y) { + this.getRoomIndex = function (x, y, cacheOnly) { + if (this.rooms.length > 25) { + this.reset(); + } + var i; for (i = 0; i < this.rooms.length; i += 1) { @@ -48,7 +87,7 @@ var CollMap = new function () { } } - if (this.addRoom(x, y)) { + if (!cacheOnly && this.addRoom(x, y)) { return i; } @@ -56,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; } @@ -70,20 +109,23 @@ var CollMap = new function () { // Check collision between unitA and unitB. true = collision present, false = collision not present // If checking for blocking collisions (0x1, 0x4), true means blocked, false means not blocked - this.checkColl = function (unitA, unitB, coll) { + this.checkColl = function (unitA, unitB, coll, thickness) { + if (thickness === undefined) { + thickness = 1; + } + var i, k, l, cx, cy, angle, distance; - angle = Math.round(Math.atan2(unitA.y - unitB.y, unitA.x - unitB.x) * 180 / Math.PI); + angle = Math.atan2(unitA.y - unitB.y, unitA.x - unitB.x); distance = Math.round(getDistance(unitA, unitB)); -MainLoop: for (i = 1; i < distance; i += 1) { - cx = Math.round((Math.cos(angle * Math.PI / 180)) * i + unitB.x); - cy = Math.round((Math.sin(angle * Math.PI / 180)) * i + unitB.y); + cx = Math.round((Math.cos(angle)) * i + unitB.x); + cy = Math.round((Math.sin(angle)) * i + unitB.y); - for (k = cx - 1; k <= cx + 1; k += 1) { // check thicker line - for (l = cy - 1; l <= cy + 1; l += 1) { - if (this.getColl(k, l) & coll) { + for (k = cx - thickness; k <= cx + thickness; k += 1) { // check thicker line + for (l = cy - thickness; l <= cy + thickness; l += 1) { + if (this.getColl(k, l, false) & coll) { return true; } } diff --git a/d2bs/kolbot/libs/common/Config.js b/d2bs/kolbot/libs/common/Config.js index ecd413ff6..f6b108583 100644 --- a/d2bs/kolbot/libs/common/Config.js +++ b/d2bs/kolbot/libs/common/Config.js @@ -8,29 +8,86 @@ var Scripts = {}; var Config = { init: function (notify) { - var classes = ["Amazon", "Sorceress", "Necromancer", "Paladin", "Barbarian", "Druid", "Assassin"]; + var i, n, + configFilename = "", + classes = ["Amazon", "Sorceress", "Necromancer", "Paladin", "Barbarian", "Druid", "Assassin"]; - if (!FileTools.exists("libs/config/" + classes[me.classid] + "." + me.charname + ".js")) { + for (i = 0; i < 5; i += 1) { + switch (i) { + case 0: // Custom config + if (!isIncluded("config/_customconfig.js")) { + include("config/_customconfig.js"); + } + + for (n in CustomConfig) { + if (CustomConfig.hasOwnProperty(n)) { + if (CustomConfig[n].indexOf(me.profile) > -1) { + if (notify) { + print("ÿc2Loading custom config: ÿc9" + n + ".js"); + } + + configFilename = n + ".js"; + + break; + } + } + } + + break; + case 1:// Class.Profile.js + configFilename = classes[me.classid] + "." + me.profile + ".js"; + + break; + case 2: // Realm.Class.Charname.js + configFilename = me.realm + "." + classes[me.classid] + "." + me.charname + ".js"; + + break; + case 3: // Class.Charname.js + configFilename = classes[me.classid] + "." + me.charname + ".js"; + + break; + case 4: // Profile.js + configFilename = me.profile + ".js"; + + break; + } + + if (configFilename && FileTools.exists("libs/config/" + configFilename)) { + break; + } + } + + 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!"); + print("ÿc1" + classes[me.classid] + "." + me.charname + ".js not found!"); // Use the primary format print("ÿc1Loading 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."); + } + try { - include("config/" + classes[me.classid] + ".js"); + if (!include("config/" + classes[me.classid] + ".js")) { + throw new Error(); + } } catch (e) { - throw new Error("Failed to load default config."); + throw new Error("ÿc1Failed to load default config."); } } try { - include("config/" + classes[me.classid] + "." + me.charname + ".js"); - } catch (e1) { - throw new Error("Failed to load default config."); - } - - try { - LoadConfig(); + LoadConfig.call(); } catch (e2) { if (notify) { print("ÿc8Error in " + e2.fileName.substring(e2.fileName.lastIndexOf("\\") + 1, e2.fileName.length) + "(line " + e2.lineNumber + "): " + e2.message); @@ -38,6 +95,15 @@ var Config = { throw new Error("Config.init: Error in character config."); } } + + 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(e3.toSource()); + } }, // Time @@ -60,15 +126,24 @@ var Config = { IronGolemChicken: 0, HealHP: 0, HealMP: 0, + HealStatus: false, TownHP: 0, 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, @@ -81,10 +156,20 @@ var Config = { [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] ], PublicMode: false, + PartyAfterScript: false, + Greetings: [], + 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: [], @@ -93,8 +178,15 @@ var Config = { SkipEnchant: [], SkipImmune: [], SkipAura: [], + ScanShrines: [], + Debug: false, + + ItemInfo: false, + ItemInfoQuality: [], Cubing: false, + CubeRepair: false, + RepairPercent: 40, Recipes: [], MakeRunewords: false, Runewords: [], @@ -105,28 +197,56 @@ var Config = { GambleGoldStop: 0, MiniShopBot: false, TeleSwitch: false, + MFSwitch: 0, + MFSwitchPercent: 0, LogExperience: false, TownCheck: false, + PingQuit: [{Ping: 0, Duration: 0}], + PacketShopping: false, + + // Fastmod + FCR: 0, + FHR: 0, + FBR: 0, + IAS: 0, + PacketCasting: 0, + WaypointMenu: false, // Anti-hostile AntiHostile: false, + RandomPrecast: false, HostileAction: 0, + TownOnHostile: false, + ViperCheck: false, // DClone StopOnDClone: false, SoJWaitTime: 0, + KillDclone: false, + DCloneQuit: false, + + // Experimental + FastParty: false, + AutoEquip: false, // Attack specific Dodge: false, + DodgeRange: 15, + DodgeHP: 100, AttackSkill: [], + LowManaSkill: [], + CustomAttack: {}, TeleStomp: false, ClearType: false, + ClearPath: false, BossPriority: false, // Amazon specific + LightningFuryDelay: 0, SummonValkyrie: false, // Sorceress specific + UseTelekinesis: false, CastStatic: false, StaticList: [], @@ -143,6 +263,7 @@ var Config = { // Paladin speficic Redemption: [0, 0], + Charge: false, Vigor: false, AvoidDolls: false, @@ -152,6 +273,7 @@ var Config = { FindItemSwitch: 1, // Druid specific + Wereform: 0, SummonRaven: 0, SummonAnimal: 0, SummonVine: 0, @@ -180,6 +302,7 @@ var Config = { KillDacFarren: false }, Pindleskin: { + UseWaypoint: false, KillNihlathak: false, ViperQuit: false }, @@ -200,7 +323,10 @@ var Config = { KillGriswold: false }, AutoBaal: { - FindShrine: false + Leader: "", + FindShrine: false, + LeechSpot: [15115, 5050], + LongRangeSupport: false }, KurastChests: { LowerKurast: false, @@ -212,15 +338,37 @@ var Config = { KillGhosts: false }, Baal: { - HotTPMsg: "Hot TP!", - SafeTPMsg: "TP safe!", - BaalMsg: "Baal", - DollQuit: false + DollQuit: false, + SoulQuit: false, + KillBaal: false, + HotTPMessage: "Hot TP!", + SafeTPMessage: "Safe TP!", + BaalMessage: "Baal!" + }, + BaalAssistant: { + KillNihlathak: false, + FastChaos: false, + Wait: 120, + Helper: false, + GetShrine: false, + GetShrineWaitForHotTP: false, + DollQuit: false, + SoulQuit: false, + SkipTP: false, + WaitForSafeTP: false, + KillBaal: false, + HotTPMessage: [], + SafeTPMessage: [], + BaalMessage: [], + NextGameMessage: [] }, BaalHelper: { + Wait: 120, KillNihlathak: false, FastChaos: false, - DollQuit: false + DollQuit: false, + KillBaal: false, + SkipTP: false }, Corpsefire: { ClearDen: false @@ -229,17 +377,24 @@ var Config = { Entrance: false, SealWarning: "Leave the seals alone!", EntranceTP: "Entrance TP up", - StarTP: "Star TP up" + StarTP: "Star TP up", + DiabloMsg: "Diablo" }, DiabloHelper: { - Entrance: false + Wait: 120, + Entrance: false, + SkipIfBaal: false, + SkipTP: false }, BattleOrders: { Mode: 0, + Getters: [], Wait: false }, Enchant: { - Trigger: ".chant", + Triggers: ["chant", "cows", "wps"], + GetLeg: false, + AutoChant: false, GameLength: 20 }, IPHunter: { @@ -250,10 +405,85 @@ var Config = { Leader: "" }, Mephisto: { - MoatTrick: false + MoatTrick: false, + KillCouncil: false, + TakeRedPortal: false }, ShopBot: { ScanIDs: [], - ShopNPC: "anya" + ShopNPC: "anya", + CycleDelay: 0, + QuitOnMatch: false + }, + Coldworm: { + KillBeetleburst: false, + ClearMaggotLair: false + }, + Summoner: { + FireEye: false + }, + AncientTunnels: { + OpenChest: false, + KillDarkElder: false + }, + OrgTorch: { + WaitForKeys: false, + WaitTimeout: false, + UseSalvation: false, + GetFade: false, + MakeTorch: true + }, + Synch: { + WaitFor: [] + }, + TristramLeech: { + Leader: "", + Wait: 120 + }, + TravincalLeech: { + Leader: "", + Helper: false, + Wait: 120 + }, + Tristram: { + PortalLeech: false + }, + Travincal: { + PortalLeech: false + }, + SkillStat: { + Skills: [] + }, + Bonesaw: { + ClearDrifterCavern: false + }, + ChestMania: { + Act1: [], + Act2: [], + Act3: [], + Act4: [], + Act5: [] + }, + ClearAnyArea: { + AreaList: [] + }, + Rusher: { + WaitPlayerCount: 0, + Radament: false, + LamEsen: false, + Izual: false, + Shenk: false, + Anya: false, + LastRun: "" + }, + Rushee: { + Quester: false, + Bumper: false + }, + AutoBuild: { + Enabled: false, + Template: "", + Verbose: false, + DebugMode: false } -}; \ No newline at end of file +}; diff --git a/d2bs/kolbot/libs/common/Cubing.js b/d2bs/kolbot/libs/common/Cubing.js index f2b630c7b..cb7929a0c 100644 --- a/d2bs/kolbot/libs/common/Cubing.js +++ b/d2bs/kolbot/libs/common/Cubing.js @@ -4,6 +4,13 @@ * @desc transmute Horadric Cube recipes */ + +var Roll = { + All: 0, + Eth: 1, + NonEth: 2 +}; + var Recipe = { Gem: 0, HitPower: { @@ -78,277 +85,490 @@ var Recipe = { }, Reroll: { Magic: 49, - Rare: 50 + Rare: 50, + HighRare: 51 }, - Rune: 51, - Token: 52 + Rune: 52, + Token: 53, + LowToNorm: { + Armor: 54, + Weapon: 55 + } }; var Cubing = { recipes: [], + gemList: [], init: function () { if (!Config.Cubing) { return; } - print("We have " + Config.Recipes.length + " cubing recipe(s)."); + //print("We have " + Config.Recipes.length + " cubing recipe(s)."); + + var i; + + for (i = 0; i < Config.Recipes.length; i += 1) { + if (Config.Recipes[i].length > 1 && isNaN(Config.Recipes[i][1])) { + if (NTIPAliasClassID.hasOwnProperty(Config.Recipes[i][1].replace(/\s+/g, "").toLowerCase())) { + Config.Recipes[i][1] = NTIPAliasClassID[Config.Recipes[i][1].replace(/\s+/g, "").toLowerCase()]; + } else { + Misc.errorReport("ÿc1Invalid cubing entry:ÿc0 " + Config.Recipes[i][1]); + Config.Recipes.splice(i, 1); + + i -= 1; + } + } + } this.buildRecipes(); + this.buildGemList(); this.buildLists(); }, + buildGemList: function () { + var i, j, + gemList = [ItemClassIds.Perfect_Amethyst, ItemClassIds.Perfect_Topaz, ItemClassIds.Perfect_Sapphire, ItemClassIds.Perfect_Emerald, ItemClassIds.Perfect_Ruby, ItemClassIds.Perfect_Diamond, ItemClassIds.Perfect_Skull]; + + for (i = 0; i < this.recipes.length; i += 1) { + if ([0, 49].indexOf(this.recipes[i].Index) === -1) { // Skip gems and other magic rerolling recipes + for (j = 0; j < this.recipes[i].Ingredients.length; j += 1) { + if (gemList.indexOf(this.recipes[i].Ingredients[j]) > -1) { + gemList.splice(gemList.indexOf(this.recipes[i].Ingredients[j]), 1); + } + } + } + } + + this.gemList = gemList.slice(0); + + return true; + }, + + getCube: function () { + // Don't activate from townchicken + if (getScript(true).name === "tools\\townchicken.js") { + return false; + } + + var i, cube, chest; + + Pather.useWaypoint(Areas.Act2.Halls_Of_The_Dead_Level_2, true); + Precast.doPrecast(true); + + if (Pather.moveToExit(Areas.Act2.Halls_Of_The_Dead_Level_3, true) && Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Horadric_Cube_Chest)) { + chest = getUnit(UnitType.Object, UniqueObjectIds.Horadric_Cube_Chest); + + if (chest) { + Misc.openChest(chest); + + for (i = 0; i < 5; i += 1) { + cube = getUnit(UnitType.Item, ItemClassIds.Horadric_Cube); + + if (cube) { + Pickit.pickItem(cube); + + break; + } + + delay(200); + } + } + } + + Town.goToTown(); + + cube = me.getItem(ItemClassIds.Horadric_Cube); + + if (cube) { + return Storage.Stash.MoveTo(cube); + } + + return false; + }, + buildRecipes: function () { var i; this.recipes = []; for (i = 0; i < Config.Recipes.length; i += 1) { - if (typeof Config.Recipes[i] !== "object" || Config.Recipes[i].length > 2 || Config.Recipes[i].length < 1) { + if (typeof Config.Recipes[i] !== "object" || (Config.Recipes[i].length > 2 && typeof Config.Recipes[i][2] !== "number") || Config.Recipes[i].length < 1) { throw new Error("Cubing.buildRecipes: Invalid recipe format."); } switch (Config.Recipes[i][0]) { case Recipe.Gem: - this.recipes.push({Ingredients: [Config.Recipes[i][1], Config.Recipes[i][1], Config.Recipes[i][1]], Index: Recipe.Gem, Enabled: true}); + this.recipes.push({Ingredients: [Config.Recipes[i][1], Config.Recipes[i][1], Config.Recipes[i][1]], Index: Recipe.Gem, AlwaysEnabled: true}); + break; case Recipe.HitPower.Helm: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 615, 643, 571], Level: 93, Index: Recipe.HitPower.Helm}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ith_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Sapphire], Level: 84, Index: Recipe.HitPower.Helm }); + break; case Recipe.HitPower.Boots: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 617, 643, 571], Level: 93, Index: Recipe.HitPower.Boots}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ral_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Sapphire], Level: 71, Index: Recipe.HitPower.Boots}); + break; case Recipe.HitPower.Gloves: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 618, 643, 571], Level: 93, Index: Recipe.HitPower.Gloves}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ort_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Sapphire], Level: 79, Index: Recipe.HitPower.Gloves}); + break; case Recipe.HitPower.Belt: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 616, 643, 571], Level: 93, Index: Recipe.HitPower.Belt}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Tal_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Sapphire], Level: 71, Index: Recipe.HitPower.Belt}); + break; case Recipe.HitPower.Shield: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 614, 643, 571], Level: 93, Index: Recipe.HitPower.Shield}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Eth_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Sapphire], Level: 82, Index: Recipe.HitPower.Shield}); + break; case Recipe.HitPower.Body: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 613, 643, 571], Level: 93, Index: Recipe.HitPower.Body}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Nef_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Sapphire], Level: 85, Index: Recipe.HitPower.Body}); + break; case Recipe.HitPower.Amulet: - this.recipes.push({Ingredients: [520, 619, 643, 571], Level: 93, Index: Recipe.HitPower.Amulet}); + this.recipes.push({ Ingredients: [ItemClassIds.Amulet, ItemClassIds.Thul_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Sapphire], Level: 90, Index: Recipe.HitPower.Amulet}); + break; case Recipe.HitPower.Ring: - this.recipes.push({Ingredients: [522, 620, 643, 571], Level: 93, Index: Recipe.HitPower.Ring}); + this.recipes.push({ Ingredients: [ItemClassIds.Ring, ItemClassIds.Amn_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Sapphire], Level: 77, Index: Recipe.HitPower.Ring}); + break; case Recipe.HitPower.Weapon: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 612, 643, 571], Level: 93, Index: Recipe.HitPower.Weapon}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Tir_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Sapphire], Level: 85, Index: Recipe.HitPower.Weapon}); + break; case Recipe.Blood.Helm: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 617, 643, 581], Level: 93, Index: Recipe.Blood.Helm}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ral_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Ruby], Level: 84, Index: Recipe.Blood.Helm}); + break; case Recipe.Blood.Boots: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 614, 643, 581], Level: 93, Index: Recipe.Blood.Boots}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Eth_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Ruby], Level: 71, Index: Recipe.Blood.Boots}); + break; case Recipe.Blood.Gloves: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 613, 643, 581], Level: 93, Index: Recipe.Blood.Gloves}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Nef_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Ruby], Level: 79, Index: Recipe.Blood.Gloves}); + break; case Recipe.Blood.Belt: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 616, 643, 581], Level: 93, Index: Recipe.Blood.Belt}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Tal_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Ruby], Level: 71, Index: Recipe.Blood.Belt}); + break; case Recipe.Blood.Shield: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 615, 643, 581], Level: 93, Index: Recipe.Blood.Shield}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ith_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Ruby], Level: 82, Index: Recipe.Blood.Shield}); + break; case Recipe.Blood.Body: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 619, 643, 581], Level: 93, Index: Recipe.Blood.Body}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Thul_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Ruby], Level: 85, Index: Recipe.Blood.Body}); + break; case Recipe.Blood.Amulet: - this.recipes.push({Ingredients: [520, 620, 643, 581], Level: 93, Index: Recipe.Blood.Amulet}); + this.recipes.push({ Ingredients: [ItemClassIds.Amulet, ItemClassIds.Amn_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Ruby], Level: 90, Index: Recipe.Blood.Amulet}); + break; case Recipe.Blood.Ring: - this.recipes.push({Ingredients: [522, 621, 643, 581], Level: 93, Index: Recipe.Blood.Ring}); + this.recipes.push({ Ingredients: [ItemClassIds.Ring, ItemClassIds.Sol_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Ruby], Level: 77, Index: Recipe.Blood.Ring}); + break; case Recipe.Blood.Weapon: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 618, 643, 581], Level: 93, Index: Recipe.Blood.Weapon}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ort_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Ruby], Level: 85, Index: Recipe.Blood.Weapon}); + break; case Recipe.Caster.Helm: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 613, 643, 561], Level: 93, Index: Recipe.Caster.Helm}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Nef_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Amethyst], Level: 84, Index: Recipe.Caster.Helm}); + break; case Recipe.Caster.Boots: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 619, 643, 561], Level: 93, Index: Recipe.Caster.Boots}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Thul_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Amethyst], Level: 71, Index: Recipe.Caster.Boots}); + break; case Recipe.Caster.Gloves: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 618, 643, 561], Level: 93, Index: Recipe.Caster.Gloves}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ort_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Amethyst], Level: 79, Index: Recipe.Caster.Gloves}); + break; case Recipe.Caster.Belt: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 615, 643, 561], Level: 93, Index: Recipe.Caster.Belt}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ith_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Amethyst], Level: 71, Index: Recipe.Caster.Belt}); + break; case Recipe.Caster.Shield: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 614, 643, 561], Level: 93, Index: Recipe.Caster.Shield}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Eth_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Amethyst], Level: 82, Index: Recipe.Caster.Shield}); + break; case Recipe.Caster.Body: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 616, 643, 561], Level: 93, Index: Recipe.Caster.Body}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Tal_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Amethyst], Level: 85, Index: Recipe.Caster.Body}); + break; case Recipe.Caster.Amulet: - this.recipes.push({Ingredients: [520, 617, 643, 561], Level: 93, Index: Recipe.Caster.Amulet}); + this.recipes.push({ Ingredients: [ItemClassIds.Amulet, ItemClassIds.Ral_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Amethyst], Level: 90, Index: Recipe.Caster.Amulet}); + break; case Recipe.Caster.Ring: - this.recipes.push({Ingredients: [522, 620, 643, 561], Level: 93, Index: Recipe.Caster.Ring}); + this.recipes.push({ Ingredients: [ItemClassIds.Ring, ItemClassIds.Amn_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Amethyst], Level: 77, Index: Recipe.Caster.Ring}); + break; case Recipe.Caster.Weapon: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 612, 643, 561], Level: 93, Index: Recipe.Caster.Weapon}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Tir_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Amethyst], Level: 85, Index: Recipe.Caster.Weapon}); + break; case Recipe.Safety.Helm: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 615, 643, 576], Level: 93, Index: Recipe.Safety.Helm}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ith_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Emerald], Level: 84, Index: Recipe.Safety.Helm}); + break; case Recipe.Safety.Boots: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 618, 643, 576], Level: 93, Index: Recipe.Safety.Boots}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ort_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Emerald], Level: 71, Index: Recipe.Safety.Boots}); + break; case Recipe.Safety.Gloves: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 617, 643, 576], Level: 93, Index: Recipe.Safety.Gloves}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ral_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Emerald], Level: 79, Index: Recipe.Safety.Gloves}); + break; case Recipe.Safety.Belt: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 616, 643, 576], Level: 93, Index: Recipe.Safety.Belt}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Tal_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Emerald], Level: 71, Index: Recipe.Safety.Belt}); + break; case Recipe.Safety.Shield: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 613, 643, 576], Level: 93, Index: Recipe.Safety.Shield}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Nef_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Emerald], Level: 82, Index: Recipe.Safety.Shield}); + break; case Recipe.Safety.Body: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 614, 643, 576], Level: 93, Index: Recipe.Safety.Body}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Eth_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Emerald], Level: 85, Index: Recipe.Safety.Body}); + break; case Recipe.Safety.Amulet: - this.recipes.push({Ingredients: [520, 619, 643, 576], Level: 93, Index: Recipe.Safety.Amulet}); + this.recipes.push({ Ingredients: [ItemClassIds.Amulet, ItemClassIds.Thul_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Emerald], Level: 90, Index: Recipe.Safety.Amulet}); + break; case Recipe.Safety.Ring: - this.recipes.push({Ingredients: [522, 620, 643, 576], Level: 93, Index: Recipe.Safety.Ring}); + this.recipes.push({ Ingredients: [ItemClassIds.Ring, ItemClassIds.Amn_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Emerald], Level: 77, Index: Recipe.Safety.Ring}); + break; case Recipe.Safety.Weapon: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 621, 643, 576], Level: 93, Index: Recipe.Safety.Weapon}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Sol_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Emerald], Level: 85, Index: Recipe.Safety.Weapon}); + break; case Recipe.Unique.Weapon.ToExceptional: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 617, 621, 576], Index: Recipe.Unique.Weapon.ToExceptional}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ral_Rune, ItemClassIds.Jewel, ItemClassIds.Perfect_Emerald], 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}); + case Recipe.Unique.Weapon.ToElite: // Ladder only + if (me.ladder) { + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Lum_Rune, ItemClassIds.Pul_Rune, ItemClassIds.Perfect_Emerald], 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}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Tal_Rune, ItemClassIds.Shael_Rune, ItemClassIds.Perfect_Diamond], 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}); + case Recipe.Unique.Armor.ToElite: // Ladder only + if (me.ladder) { + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Lem_Rune, ItemClassIds.Ko_Rune, ItemClassIds.Perfect_Diamond], Index: Recipe.Unique.Armor.ToElite, Ethereal: Config.Recipes[i][2]}); + } + break; case Recipe.Rare.Weapon.ToExceptional: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 618, 620, 571], Index: Recipe.Rare.Weapon.ToExceptional}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ort_Rune, ItemClassIds.Amn_Rune, ItemClassIds.Perfect_Sapphire], Index: Recipe.Rare.Weapon.ToExceptional, Ethereal: Config.Recipes[i][2]}); + break; case Recipe.Rare.Weapon.ToElite: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 628, 631, 571], Index: Recipe.Rare.Weapon.ToElite}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Fal_Rune, ItemClassIds.Um_Rune, ItemClassIds.Perfect_Sapphire], Index: Recipe.Rare.Weapon.ToElite, Ethereal: Config.Recipes[i][2]}); + break; case Recipe.Rare.Armor.ToExceptional: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 617, 619, 561], Index: Recipe.Rare.Armor.ToExceptional}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ral_Rune, ItemClassIds.Thul_Rune, ItemClassIds.Perfect_Amethyst], Index: Recipe.Rare.Armor.ToExceptional, Ethereal: Config.Recipes[i][2]}); + break; case Recipe.Rare.Armor.ToElite: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 627, 630, 561], Index: Recipe.Rare.Armor.ToElite}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ko_Rune, ItemClassIds.Pul_Rune, ItemClassIds.Perfect_Amethyst], Index: Recipe.Rare.Armor.ToElite, Ethereal: Config.Recipes[i][2]}); + break; case Recipe.Socket.Shield: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 616, 620, 581], Index: Recipe.Socket.Shield}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Tal_Rune, ItemClassIds.Amn_Rune, ItemClassIds.Perfect_Ruby], Index: Recipe.Socket.Shield, Ethereal: Config.Recipes[i][2]}); + break; case Recipe.Socket.Weapon: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 617, 620, 561], Index: Recipe.Socket.Weapon}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ral_Rune, ItemClassIds.Amn_Rune, ItemClassIds.Perfect_Amethyst], Index: Recipe.Socket.Weapon, Ethereal: Config.Recipes[i][2]}); + break; case Recipe.Socket.Armor: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 616, 619, 566], Index: Recipe.Socket.Armor}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Tal_Rune, ItemClassIds.Thul_Rune, ItemClassIds.Perfect_Topaz], Index: Recipe.Socket.Armor, Ethereal: Config.Recipes[i][2]}); + break; case Recipe.Socket.Helm: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 617, 619, 571], Index: Recipe.Socket.Helm}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Ral_Rune, ItemClassIds.Thul_Rune, ItemClassIds.Perfect_Sapphire], Index: Recipe.Socket.Helm, Ethereal: Config.Recipes[i][2]}); + break; case Recipe.Reroll.Magic: // Hacky solution ftw - this.recipes.push({Ingredients: [Config.Recipes[i][1], "pgem", "pgem", "pgem"], Level: 90, Index: Recipe.Reroll.Magic}); + this.recipes.push({Ingredients: [Config.Recipes[i][1], "pgem", "pgem", "pgem"], Level: 91, Index: Recipe.Reroll.Magic}); + break; case Recipe.Reroll.Rare: - this.recipes.push({Ingredients: [Config.Recipes[i][1], 601, 601, 601, 601, 601, 601], Index: Recipe.Reroll.Rare}); + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Perfect_Skull, ItemClassIds.Perfect_Skull, ItemClassIds.Perfect_Skull, ItemClassIds.Perfect_Skull, ItemClassIds.Perfect_Skull, ItemClassIds.Perfect_Skull], Index: Recipe.Reroll.Rare}); + + break; + case Recipe.Reroll.HighRare: + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Perfect_Skull, ItemClassIds.Ring], Index: Recipe.Reroll.HighRare, Enabled: false}); + + break; + case Recipe.LowToNorm.Weapon: + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.Eld_Rune, "cgem"], Index: Recipe.LowToNorm.Weapon}); + + break; + case Recipe.LowToNorm.Armor: + this.recipes.push({ Ingredients: [Config.Recipes[i][1], ItemClassIds.El_Rune, "cgem"], Index: Recipe.LowToNorm.Armor}); + break; case Recipe.Rune: switch (Config.Recipes[i][1]) { - case 610: // el - case 611: // eld - case 612: // tir - case 613: // nef - case 614: // eth - case 615: // ith - case 616: // tal - case 617: // ral - case 618: // ort - this.recipes.push({Ingredients: [Config.Recipes[i][1], Config.Recipes[i][1], Config.Recipes[i][1]], Index: Recipe.Rune, Enabled: true}); + case ItemClassIds.El_Rune: // el + case ItemClassIds.Eld_Rune: // eld + case ItemClassIds.Tir_Rune: // tir + case ItemClassIds.Nef_Rune: // nef + case ItemClassIds.Eth_Rune: // eth + case ItemClassIds.Ith_Rune: // ith + case ItemClassIds.Tal_Rune: // tal + case ItemClassIds.Ral_Rune: // ral + case ItemClassIds.Ort_Rune: // ort + 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 - this.recipes.push({Ingredients: [619, 619, 619, 562], Index: Recipe.Rune}); + case ItemClassIds.Thul_Rune: // thul->amn + this.recipes.push({ Ingredients: [ItemClassIds.Thul_Rune, ItemClassIds.Thul_Rune, ItemClassIds.Thul_Rune, ItemClassIds.Chipped_Topaz], Index: Recipe.Rune}); + break; - case 620: // amn - this.recipes.push({Ingredients: [620, 620, 620, 557], Index: Recipe.Rune}); + case ItemClassIds.Amn_Rune: // amn->sol + this.recipes.push({ Ingredients: [ItemClassIds.Amn_Rune, ItemClassIds.Amn_Rune, ItemClassIds.Amn_Rune, ItemClassIds.Chipped_Amethyst], Index: Recipe.Rune}); + break; - case 621: // sol - this.recipes.push({Ingredients: [621, 621, 621, 567], Index: Recipe.Rune}); + case ItemClassIds.Sol_Rune: // sol->shael + this.recipes.push({ Ingredients: [ItemClassIds.Sol_Rune, ItemClassIds.Sol_Rune, ItemClassIds.Sol_Rune, ItemClassIds.Chipped_Sapphire], Index: Recipe.Rune}); + break; - case 622: // shael - this.recipes.push({Ingredients: [622, 622, 622, 577], Index: Recipe.Rune}); + case ItemClassIds.Shael_Rune: // shael->dol + this.recipes.push({ Ingredients: [ItemClassIds.Shael_Rune, ItemClassIds.Shael_Rune, ItemClassIds.Shael_Rune, ItemClassIds.Chipped_Ruby], Index: Recipe.Rune}); + break; - case 623: // dol - this.recipes.push({Ingredients: [623, 623, 623, 572], Index: Recipe.Rune}); + case ItemClassIds.Dol_Rune: // dol->hel + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Dol_Rune, ItemClassIds.Dol_Rune, ItemClassIds.Dol_Rune, ItemClassIds.Chipped_Emerald], Index: Recipe.Rune}); + } + break; - case 624: // hel - this.recipes.push({Ingredients: [624, 624, 624, 582], Index: Recipe.Rune}); + case ItemClassIds.Hel_Rune: // hel->io + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Hel_Rune, ItemClassIds.Hel_Rune, ItemClassIds.Hel_Rune, ItemClassIds.Chipped_Diamond], Index: Recipe.Rune}); + } + break; - case 625: // io - this.recipes.push({Ingredients: [625, 625, 625, 563], Index: Recipe.Rune}); + case ItemClassIds.Io_Rune: // io->lum + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Io_Rune, ItemClassIds.Io_Rune, ItemClassIds.Io_Rune, ItemClassIds.Flawed_Topaz], Index: Recipe.Rune}); + } + break; - case 626: // lum - this.recipes.push({Ingredients: [626, 626, 626, 558], Index: Recipe.Rune}); + case ItemClassIds.Lum_Rune: // lum->ko + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Lum_Rune, ItemClassIds.Lum_Rune, ItemClassIds.Lum_Rune, ItemClassIds.Flawed_Amethyst], Index: Recipe.Rune}); + } + break; - case 627: // ko - this.recipes.push({Ingredients: [627, 627, 627, 568], Index: Recipe.Rune}); + case ItemClassIds.Ko_Rune: // ko->fal + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Ko_Rune, ItemClassIds.Ko_Rune, ItemClassIds.Ko_Rune, ItemClassIds.Flawed_Sapphire], Index: Recipe.Rune}); + } + break; - case 628: // fal - this.recipes.push({Ingredients: [628, 628, 628, 578], Index: Recipe.Rune}); + case ItemClassIds.Fal_Rune: // fal->lem + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Fal_Rune, ItemClassIds.Fal_Rune, ItemClassIds.Fal_Rune, ItemClassIds.Flawed_Ruby], Index: Recipe.Rune}); + } + break; - case 629: // lem - this.recipes.push({Ingredients: [629, 629, 629, 573], Index: Recipe.Rune}); + case ItemClassIds.Lem_Rune: // lem->pul + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Lem_Rune, ItemClassIds.Lem_Rune, ItemClassIds.Lem_Rune, ItemClassIds.Flawed_Emerald], Index: Recipe.Rune}); + } + break; - case 630: // pul - this.recipes.push({Ingredients: [630, 630, 583], Index: Recipe.Rune}); + case ItemClassIds.Pul_Rune: // pul->um + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Pul_Rune, ItemClassIds.Pul_Rune, ItemClassIds.Flawed_Diamond], Index: Recipe.Rune}); + } + break; - case 631: // um - this.recipes.push({Ingredients: [631, 631, 564], Index: Recipe.Rune}); + case ItemClassIds.Um_Rune: // um->mal + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Um_Rune, ItemClassIds.Um_Rune, ItemClassIds.Topaz], Index: Recipe.Rune}); + } + break; - case 632: // mal - this.recipes.push({Ingredients: [632, 632, 559], Index: Recipe.Rune}); + case ItemClassIds.Mal_Rune: // mal->ist + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Mal_Rune, ItemClassIds.Mal_Rune, ItemClassIds.Amethyst], Index: Recipe.Rune}); + } + break; - case 633: // ist - this.recipes.push({Ingredients: [633, 633, 569], Index: Recipe.Rune}); + case ItemClassIds.Ist_Rune: // ist->gul + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Ist_Rune, ItemClassIds.Ist_Rune, ItemClassIds.Sapphire], Index: Recipe.Rune}); + } + break; - case 634: // gul - this.recipes.push({Ingredients: [634, 634, 579], Index: Recipe.Rune}); + case ItemClassIds.Gul_Rune: // gul->vex + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Gul_Rune, ItemClassIds.Gul_Rune, ItemClassIds.Ruby], Index: Recipe.Rune}); + } + break; - case 635: // vex - this.recipes.push({Ingredients: [635, 635, 574], Index: Recipe.Rune}); + case ItemClassIds.Vex_Rune: // vex->ohm + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Vex_Rune, ItemClassIds.Vex_Rune, ItemClassIds.Emerald], Index: Recipe.Rune}); + } + break; - case 636: // ohm - this.recipes.push({Ingredients: [636, 636, 584], Index: Recipe.Rune}); + case ItemClassIds.Ohm_Rune: // ohm->lo + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Ohm_Rune, ItemClassIds.Ohm_Rune, ItemClassIds.Diamond], Index: Recipe.Rune}); + } + break; - case 637: // lo - this.recipes.push({Ingredients: [637, 637, 565], Index: Recipe.Rune}); + case ItemClassIds.Lo_Rune: // lo->sur + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Lo_Rune, ItemClassIds.Lo_Rune, ItemClassIds.Flawless_Topaz], Index: Recipe.Rune}); + } + break; - case 638: // sur - this.recipes.push({Ingredients: [638, 638, 560], Index: Recipe.Rune}); + case ItemClassIds.Sur_Rune: // sur->ber + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Sur_Rune, ItemClassIds.Sur_Rune, ItemClassIds.Flawless_Amethyst], Index: Recipe.Rune}); + } + break; - case 639: // ber - this.recipes.push({Ingredients: [639, 639, 570], Index: Recipe.Rune}); + case ItemClassIds.Ber_Rune: // ber->jah + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Ber_Rune, ItemClassIds.Ber_Rune, ItemClassIds.Flawless_Sapphire], Index: Recipe.Rune}); + } + break; - case 640: // jah - this.recipes.push({Ingredients: [640, 640, 580], Index: Recipe.Rune}); + case ItemClassIds.Jah_Rune: // jah->cham + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Jah_Rune, ItemClassIds.Jah_Rune, ItemClassIds.Flawless_Ruby], Index: Recipe.Rune}); + } + break; - case 641: // cham - this.recipes.push({Ingredients: [641, 641, 575], Index: Recipe.Rune}); + case ItemClassIds.Cham_Rune: // cham->zod + if (me.ladder) { + this.recipes.push({ Ingredients: [ItemClassIds.Cham_Rune, ItemClassIds.Cham_Rune, ItemClassIds.Flawless_Emerald], Index: Recipe.Rune}); + } + break; } break; case Recipe.Token: - this.recipes.push({Ingredients: [654, 655, 656, 657], Index: Recipe.Token, Enabled: true}); + this.recipes.push({ Ingredients: [ItemClassIds.Twisted_Essence_Of_Suffering, ItemClassIds.Charged_Essence_Of_Hatred, ItemClassIds.Burning_Essence_Of_Terror, ItemClassIds.Festering_Essence_Of_Destruction], Index: Recipe.Token, AlwaysEnabled: true}); + break; } } @@ -356,26 +576,38 @@ var Cubing = { validIngredients: [], // What we have neededIngredients: [], // What we need + subRecipes: [], buildLists: function () { - var i, j, k, items, temp, - subRecipes = []; + var i, j, k, items; + + CraftingSystem.checkSubrecipes(); this.validIngredients = []; this.neededIngredients = []; - items = me.findItems(-1, 0); + items = me.findItems(-1, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); for (i = 0; i < this.recipes.length; i += 1) { -IngredientLoop: for (j = 0; j < this.recipes[i].Ingredients.length; j += 1) { + // Set default Enabled property - true if recipe is always enabled, false otherwise + this.recipes[i].Enabled = this.recipes[i].hasOwnProperty("AlwaysEnabled"); + +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" && [566, 586, 601].indexOf(items[k].classid) > -1 || items[k].classid === this.recipes[i].Ingredients[j]) && this.validItem(items[k], this.recipes[i])) { + if (((this.recipes[i].Ingredients[j] === "pgem" && this.gemList.indexOf(items[k].classid) > -1) || + (this.recipes[i].Ingredients[j] === "cgem" && [ItemClassIds.Chipped_Amethyst, ItemClassIds.Chipped_Topaz, ItemClassIds.Chipped_Sapphire, ItemClassIds.Chipped_Emerald, ItemClassIds.Chipped_Ruby, ItemClassIds.Chipped_Diamond, ItemClassIds.Chipped_Skull].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 this.validIngredients.push({classid: items[k].classid, gid: items[k].gid}); + // Remove from item list to prevent counting the same item more than once items.splice(k, 1); - // enable the recipe if the first item is found. ingredients are organized in the way that the first item is always the base of the recipe (ring for ring crafting, armor for armor upgrading etc.) - if (this.recipes[i].Index !== Recipe.Rune || j === 1) { // Enable rune recipe after 2 found runes + k -= 1; + + // Enable recipes for gem/jewel pickup + if (this.recipes[i].Index !== Recipe.Rune || (this.recipes[i].Index === Recipe.Rune && j >= 1)) { // Enable rune recipe after 2 bases are found this.recipes[i].Enabled = true; } @@ -392,46 +624,70 @@ IngredientLoop: for (j = 0; j < this.recipes[i].Ingredients.length; j += 1) { } // if the recipe is enabled (we have the main item), add flawless gem recipes (if needed) - if (subRecipes.indexOf(561) === -1 && this.recipes[i].Ingredients[j] === 561) { - this.recipes.push({Ingredients: [560, 560, 560], Index: Recipe.Gem, Enabled: true}); - subRecipes.push(561); + + // Make perf amethyst + if (this.subRecipes.indexOf(ItemClassIds.Perfect_Amethyst) === -1 && (this.recipes[i].Ingredients[j] === ItemClassIds.Perfect_Amethyst || (this.recipes[i].Ingredients[j] === "pgem" && this.gemList.indexOf(ItemClassIds.Perfect_Amethyst) > -1))) { + this.recipes.push({ Ingredients: [ItemClassIds.Flawless_Amethyst, ItemClassIds.Flawless_Amethyst, ItemClassIds.Flawless_Amethyst], Index: Recipe.Gem, AlwaysEnabled: true, MainRecipe: this.recipes[i].Index}); + this.subRecipes.push(ItemClassIds.Perfect_Amethyst); } - if (subRecipes.indexOf(566) === -1 && (this.recipes[i].Ingredients[j] === 566 || this.recipes[i].Ingredients[j] === "pgem")) { - this.recipes.push({Ingredients: [565, 565, 565], Index: Recipe.Gem, Enabled: true}); - subRecipes.push(566); + // Make perf topaz + if (this.subRecipes.indexOf(ItemClassIds.Perfect_Topaz) === -1 && (this.recipes[i].Ingredients[j] === ItemClassIds.Perfect_Topaz || (this.recipes[i].Ingredients[j] === "pgem" && this.gemList.indexOf(ItemClassIds.Perfect_Topaz) > -1))) { + this.recipes.push({ Ingredients: [ItemClassIds.Flawless_Topaz, ItemClassIds.Flawless_Topaz, ItemClassIds.Flawless_Topaz], Index: Recipe.Gem, AlwaysEnabled: true, MainRecipe: this.recipes[i].Index}); + this.subRecipes.push(ItemClassIds.Perfect_Topaz); } - if (subRecipes.indexOf(571) === -1 && this.recipes[i].Ingredients[j] === 571) { - this.recipes.push({Ingredients: [570, 570, 570], Index: Recipe.Gem, Enabled: true}); - subRecipes.push(571); + // Make perf sapphire + if (this.subRecipes.indexOf(ItemClassIds.Perfect_Sapphire) === -1 && (this.recipes[i].Ingredients[j] === ItemClassIds.Perfect_Sapphire || (this.recipes[i].Ingredients[j] === "pgem" && this.gemList.indexOf(ItemClassIds.Perfect_Sapphire) > -1))) { + this.recipes.push({ Ingredients: [ItemClassIds.Flawless_Sapphire, ItemClassIds.Flawless_Sapphire, ItemClassIds.Flawless_Sapphire], Index: Recipe.Gem, AlwaysEnabled: true, MainRecipe: this.recipes[i].Index}); + this.subRecipes.push(ItemClassIds.Perfect_Sapphire); } - if (subRecipes.indexOf(576) === -1 && this.recipes[i].Ingredients[j] === 576) { - this.recipes.push({Ingredients: [575, 575, 575], Index: Recipe.Gem, Enabled: true}); - subRecipes.push(576); + // Make perf emerald + if (this.subRecipes.indexOf(ItemClassIds.Perfect_Emerald) === -1 && (this.recipes[i].Ingredients[j] === ItemClassIds.Perfect_Emerald || (this.recipes[i].Ingredients[j] === "pgem" && this.gemList.indexOf(ItemClassIds.Perfect_Emerald) > -1))) { + this.recipes.push({ Ingredients: [ItemClassIds.Flawless_Emerald, ItemClassIds.Flawless_Emerald, ItemClassIds.Flawless_Emerald], Index: Recipe.Gem, AlwaysEnabled: true, MainRecipe: this.recipes[i].Index}); + this.subRecipes.push(ItemClassIds.Perfect_Emerald); } - if (subRecipes.indexOf(581) === -1 && this.recipes[i].Ingredients[j] === 581) { - this.recipes.push({Ingredients: [580, 580, 580], Index: Recipe.Gem, Enabled: true}); - subRecipes.push(581); + // Make perf ruby + if (this.subRecipes.indexOf(ItemClassIds.Perfect_Ruby) === -1 && (this.recipes[i].Ingredients[j] === ItemClassIds.Perfect_Ruby || (this.recipes[i].Ingredients[j] === "pgem" && this.gemList.indexOf(ItemClassIds.Perfect_Ruby) > -1))) { + this.recipes.push({ Ingredients: [ItemClassIds.Flawless_Ruby, ItemClassIds.Flawless_Ruby, ItemClassIds.Flawless_Ruby], Index: Recipe.Gem, AlwaysEnabled: true, MainRecipe: this.recipes[i].Index}); + this.subRecipes.push(ItemClassIds.Perfect_Ruby); } - if (subRecipes.indexOf(586) === -1 && (this.recipes[i].Ingredients[j] === 586 || this.recipes[i].Ingredients[j] === "pgem")) { - this.recipes.push({Ingredients: [585, 585, 585], Index: Recipe.Gem, Enabled: true}); - subRecipes.push(586); + // Make perf diamond + if (this.subRecipes.indexOf(ItemClassIds.Perfect_Diamond) === -1 && (this.recipes[i].Ingredients[j] === ItemClassIds.Perfect_Diamond || (this.recipes[i].Ingredients[j] === "pgem" && this.gemList.indexOf(ItemClassIds.Perfect_Diamond) > -1))) { + this.recipes.push({ Ingredients: [ItemClassIds.Flawless_Diamond, ItemClassIds.Flawless_Diamond, ItemClassIds.Flawless_Diamond], Index: Recipe.Gem, AlwaysEnabled: true, MainRecipe: this.recipes[i].Index}); + this.subRecipes.push(ItemClassIds.Perfect_Diamond); } - if (subRecipes.indexOf(601) === -1 && (this.recipes[i].Ingredients[j] === 601 || this.recipes[i].Ingredients[j] === "pgem")) { - this.recipes.push({Ingredients: [600, 600, 600], Index: Recipe.Gem, Enabled: true}); - subRecipes.push(601); + // Make perf skull + if (this.subRecipes.indexOf(ItemClassIds.Perfect_Skull) === -1 && (this.recipes[i].Ingredients[j] === ItemClassIds.Perfect_Skull || (this.recipes[i].Ingredients[j] === "pgem" && this.gemList.indexOf(ItemClassIds.Perfect_Skull) > -1))) { + this.recipes.push({ Ingredients: [ItemClassIds.Flawless_Skull, ItemClassIds.Flawless_Skull, ItemClassIds.Flawless_Skull], Index: Recipe.Gem, AlwaysEnabled: true, MainRecipe: this.recipes[i].Index}); + this.subRecipes.push(ItemClassIds.Perfect_Skull); } } } }, - update: function (classid) { // TODO: expand or remove - Cubing.buildLists(); + // Remove unneeded flawless gem recipes + clearSubRecipes: function () { + var i; + + this.subRecipes = []; + + for (i = 0; i < this.recipes.length; i += 1) { + if (this.recipes[i].hasOwnProperty("MainRecipe")) { + this.recipes.splice(i, 1); + + i -= 1; + } + } + }, + + update: function () { + this.clearSubRecipes(); + this.buildLists(); }, checkRecipe: function (recipe) { @@ -441,11 +697,15 @@ IngredientLoop: for (j = 0; j < this.recipes[i].Ingredients.length; j += 1) { 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" && [566, 586, 601].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" && [ItemClassIds.Chipped_Amethyst, ItemClassIds.Chipped_Topaz, ItemClassIds.Chipped_Sapphire, ItemClassIds.Chipped_Emerald, ItemClassIds.Chipped_Ruby, ItemClassIds.Chipped_Diamond, ItemClassIds.Chipped_Skull].indexOf(this.validIngredients[j].classid) > -1) + )) { item = me.getItem(this.validIngredients[j].classid, -1, this.validIngredients[j].gid); - if (item) { - // don't repeat the same item. TODO: determine if this is still needed since it's older code + if (item && this.validItem(item, recipe)) { // 26.11.2012. check if the item actually belongs to the given recipe + // don't repeat the same item usedGids.push(this.validIngredients[j].gid); // push the item into the match list matchList.push(copyUnit(item)); @@ -465,15 +725,37 @@ IngredientLoop: for (j = 0; j < this.recipes[i].Ingredients.length; j += 1) { return matchList; }, + // debug function - get what each recipe needs + getRecipeNeeds: function (index) { + var i, + rval = " ["; + + for (i = 0; i < this.neededIngredients.length; i += 1) { + if (this.neededIngredients[i].recipe.Index === index) { + rval += this.neededIngredients[i].classid + (i === this.neededIngredients.length - 1 ? "" : " "); + } + } + + rval += "]"; + + return rval; + }, + checkItem: function (unit) { // Check an item on ground for pickup if (!Config.Cubing) { return false; } + if (this.keepItem(unit)) { + return true; + } + var i; - + for (i = 0; i < this.neededIngredients.length; i += 1) { if (unit.classid === this.neededIngredients[i].classid && this.validItem(unit, this.neededIngredients[i].recipe)) { + //debugLog("Cubing: " + unit.name + " " + this.neededIngredients[i].recipe.Index + " " + (this.neededIngredients[i].recipe.hasOwnProperty("MainRecipe") ? this.neededIngredients[i].recipe.MainRecipe : "") + this.getRecipeNeeds(this.neededIngredients[i].recipe.Index)); + return true; } } @@ -489,7 +771,7 @@ IngredientLoop: for (j = 0; j < this.recipes[i].Ingredients.length; j += 1) { var i; for (i = 0; i < this.validIngredients.length; i += 1) { - if (unit.location === 3 && unit.gid === this.validIngredients[i].gid) { + if (unit.mode === ItemModes.Item_In_Inventory_Stash_Cube_Or_Store && unit.gid === this.validIngredients[i].gid) { return true; } } @@ -498,8 +780,18 @@ IngredientLoop: for (j = 0; j < this.recipes[i].Ingredients.length; j += 1) { }, validItem: function (unit, recipe) { + // Don't use items in locked inventory space + if (unit.mode === ItemModes.Item_In_Inventory_Stash_Cube_Or_Store && unit.location === ItemLocation.Inventory && Storage.Inventory.IsLocked(unit, Config.Inventory)) { + return false; + } + + // Excluded items + if (Runewords.validGids.indexOf(unit.gid) > -1 || CraftingSystem.validGids.indexOf(unit.gid) > -1) { + return false; + } + // Gems and runes - if (unit.itemType >= 96 && unit.itemType <= 102 || unit.itemType === 74) { + if ((unit.itemType >= NTItemTypes.amethyst && unit.itemType <= NTItemTypes.skull) || unit.itemType === NTItemTypes.rune) { if (!recipe.Enabled && recipe.Ingredients[0] !== unit.classid && recipe.Ingredients[1] !== unit.classid) { return false; } @@ -509,47 +801,105 @@ IngredientLoop: for (j = 0; j < this.recipes[i].Ingredients.length; j += 1) { if (recipe.Index >= Recipe.HitPower.Helm && recipe.Index <= Recipe.Safety.Weapon) { // Junk jewels (NOT matching a pickit entry) - if (unit.itemType === 58) { - if (recipe.Enabled && NTIPCheckItem(unit) === 0) { + if (unit.itemType === NTItemTypes.jewel) { + if (recipe.Enabled && NTIP.CheckItem(unit) === 0) { return true; } - // Main item, NOT matching a pickit entry - } else if (unit.quality === 4 && Math.floor((me.charlvl + unit.ilvl) / 2) >= recipe.Level && NTIPCheckItem(unit) === 0) { + // Main item, NOT matching a pickit entry + } else if (unit.quality === ItemQuality.Magic && Math.floor(me.charlvl / 2) + Math.floor(unit.ilvl / 2) >= recipe.Level && NTIP.CheckItem(unit) === 0) { return true; } + + return false; } if (recipe.Index >= Recipe.Unique.Weapon.ToExceptional && recipe.Index <= Recipe.Unique.Armor.ToElite) { // Unique item matching pickit entry - if (unit.quality === 7 && NTIPCheckItem(unit) === 1) { - return true; + if (unit.quality === ItemQuality.Unique && NTIP.CheckItem(unit) === 1) { + switch (recipe.Ethereal) { + case 0: + case undefined: + return NTIP.CheckItem(unit) === 1; + case 1: + return unit.getFlag(ItemFlags.isEthereal) && NTIP.CheckItem(unit) === 1; + case 2: + return !unit.getFlag(ItemFlags.isEthereal) && NTIP.CheckItem(unit) === 1; + } } + + return false; } if (recipe.Index >= Recipe.Rare.Weapon.ToExceptional && recipe.Index <= Recipe.Rare.Armor.ToElite) { // Rare item matching pickit entry - if (unit.quality === 6 && NTIPCheckItem(unit) === 1) { - return true; + if (unit.quality === ItemQuality.Rare && NTIP.CheckItem(unit) === 1) { + switch (recipe.Ethereal) { + case 0: + case undefined: + return NTIP.CheckItem(unit) === 1; + case 1: + return unit.getFlag(ItemFlags.isEthereal) && NTIP.CheckItem(unit) === 1; + case 2: + return !unit.getFlag(ItemFlags.isEthereal) && NTIP.CheckItem(unit) === 1; + } } + + return false; } if (recipe.Index >= Recipe.Socket.Shield && recipe.Index <= Recipe.Socket.Helm) { // Normal item matching pickit entry, no sorcets - if (unit.quality === 2 && unit.getStat(194) === 0 && NTIPCheckItem(unit) === 1) { - return true; + if (unit.quality === ItemQuality.Normal && unit.getStat(Stats.item_numsockets) === 0) { + switch (recipe.Ethereal) { + case 0: + case undefined: + return NTIP.CheckItem(unit) === 1; + case 1: + return unit.getFlag(ItemFlags.isEthereal) && NTIP.CheckItem(unit) === 1; + case 2: + return !unit.getFlag(ItemFlags.isEthereal) && NTIP.CheckItem(unit) === 1; + } } + + return false; } if (recipe.Index === Recipe.Reroll.Magic) { - if (unit.quality === 4 && Math.floor((me.charlvl + unit.ilvl) / 2) >= recipe.Level && NTIPCheckItem(unit) === 0) { + if (unit.quality === ItemQuality.Magic && unit.ilvl >= recipe.Level && NTIP.CheckItem(unit) === 0) { return true; } + + return false; } if (recipe.Index === Recipe.Reroll.Rare) { - if (unit.quality === 6 && NTIPCheckItem(unit) === 0) { + if (unit.quality === ItemQuality.Rare && NTIP.CheckItem(unit) === 0) { + return true; + } + + return false; + } + + if (recipe.Index === Recipe.Reroll.HighRare) { + if (recipe.Ingredients[0] === unit.classid && unit.quality === ItemQuality.Rare && NTIP.CheckItem(unit) === 0) { + recipe.Enabled = true; + + return true; + } + + if (recipe.Enabled && recipe.Ingredients[2] === unit.classid && unit.itemType === NTItemTypes.ring && unit.getStat(Stats.item_maxmana_percent) && !Storage.Inventory.IsLocked(unit, Config.Inventory)) { + return true; + } + + return false; + } + + if (recipe.Index === Recipe.LowToNorm.Armor || recipe.Index === Recipe.LowToNorm.Weapon) { + if (unit.quality === ItemQuality.Low_Quality && NTIP.CheckItem(unit) === 0) { return true; } + + return false; } if (recipe.Index === Recipe.Token) { @@ -564,22 +914,31 @@ IngredientLoop: for (j = 0; j < this.recipes[i].Ingredients.length; j += 1) { return false; } - var i, j, items, string; + if (!me.getItem(ItemClassIds.Horadric_Cube) && !this.getCube()) { + return false; + } + + var i, j, items, string, result, tempArray; - for (i = 0; i < this.recipes.length; i += 1) { - string = "Transmuting"; - items = this.checkRecipe(this.recipes[i]); + // Randomize the recipe array to prevent recipe blocking (multiple caster items etc.) + tempArray = this.recipes.slice().shuffle(); + + for (i = 0; i < tempArray.length; i += 1) { + string = "Transmuting: "; + items = this.checkRecipe(tempArray[i]); if (items) { // If cube isn't open, attempt to open stash (the function returns true if stash is already open) - if (!getUIFlag(0x1a) && !Town.openStash() || !this.emptyCube()) { - return false + if ((!getUIFlag(UIFlags.Cube_is_open) && !Town.openStash()) || !this.emptyCube()) { + return false; } + this.cursorCheck(); + i = -1; while (items.length) { - string += (" " + items[0].name) + string += (items[0].name.trim() + (items.length > 1 ? " + " : "")); Storage.Cube.MoveTo(items[0]); items.shift(); } @@ -591,34 +950,75 @@ IngredientLoop: for (j = 0; j < this.recipes[i].Ingredients.length; j += 1) { transmute(); delay(700 + me.ping); print("ÿc4Cubing: " + string); - D2Bot.printToConsole(string); + D2Bot.printToConsole(string, 5); + this.update(); - items = me.findItems(-1, -1, 6); + items = me.findItems(-1, -1, ItemLocation.Cube); if (items) { for (j = 0; j < items.length; j += 1) { - switch (Pickit.checkItem(items[j])) { + result = Pickit.checkItem(items[j]); + + switch (result.result) { case 0: + Misc.itemLogger("Dropped", items[j], "doCubing"); items[j].drop(); + break; case 1: - Misc.logItem("Cubing kept", items[j]); + Misc.itemLogger("Cubing Kept", items[j]); + Misc.logItem("Cubing Kept", items[j], result.line); + + break; + case 5: // Crafting System + CraftingSystem.update(items[j]); + break; } } } - this.buildLists(); - if (!this.emptyCube()) { break; } } } - while (getUIFlag(0x1A) || getUIFlag(0x19)) { - me.cancel(); - delay(300) + if (getUIFlag(UIFlags.Cube_is_open) || getUIFlag(UIFlags.Stash_is_open)) { + delay(1000); + + while (getUIFlag(UIFlags.Cube_is_open) || getUIFlag(UIFlags.Stash_is_open)) { + me.cancel(); + delay(300); + } + } + + return true; + }, + + cursorCheck: function () { + var item; + + if (me.itemoncursor) { + item = getUnit(Cursor_Item.Warp); + + if (item) { + if (Storage.Inventory.CanFit(item) && Storage.Inventory.MoveTo(item)) { + return true; + } + + if (Storage.Stash.CanFit(item) && Storage.Stash.MoveTo(item)) { + return true; + } + + Misc.itemLogger("Dropped", item, "cursorCheck"); + + if (item.drop()) { + return true; + } + } + + return false; } return true; @@ -626,19 +1026,23 @@ IngredientLoop: for (j = 0; j < this.recipes[i].Ingredients.length; j += 1) { openCube: function () { var i, tick, - cube = me.getItem(549); + cube = me.getItem(ItemClassIds.Horadric_Cube); if (!cube) { return false; } + if (getUIFlag(UIFlags.Cube_is_open)) { + return true; + } + for (i = 0; i < 3; i += 1) { cube.interact(); tick = getTickCount(); while (getTickCount() - tick < 1000) { - if (getUIFlag(0x1A)) { + if (getUIFlag(UIFlags.Cube_is_open)) { delay(500); return true; @@ -652,8 +1056,8 @@ IngredientLoop: for (j = 0; j < this.recipes[i].Ingredients.length; j += 1) { }, emptyCube: function () { - var cube = me.getItem(549), - items = me.findItems(-1, -1, 6); + var cube = me.getItem(ItemClassIds.Horadric_Cube), + items = me.findItems(-1, -1, ItemLocation.Cube); if (!cube) { return false; @@ -666,6 +1070,8 @@ IngredientLoop: for (j = 0; j < this.recipes[i].Ingredients.length; j += 1) { 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/Enums.js b/d2bs/kolbot/libs/common/Enums.js new file mode 100644 index 000000000..1eb066a38 --- /dev/null +++ b/d2bs/kolbot/libs/common/Enums.js @@ -0,0 +1,4112 @@ +/** +* @filename Enums.js +* @author crenox- +* @desc enums for everything +*/ +var Skills = { + None: -1, + common: { + Attack: 0, + Kick: 1, + Throw: 2, + Unsummon: 3, + Left_Hand_Throw: 4, + Left_Hand_Swing: 5, + Scroll_of_Identify: 217, + Book_of_Identify: 218, + Scroll_of_Townportal: 219, + Book_of_Townportal: 220 + }, + Amazon: { + Magic_Arrow: 6, + Fire_Arrow: 7, + Inner_Sight: 8, + Critical_Strike: 9, + Jab: 10, + Cold_Arrow: 11, + Multiple_Shot: 12, + Dodge: 13, + Power_Strike: 14, + Poison_Javelin: 15, + Exploding_Arrow: 16, + Slow_Missiles: 17, + Avoid: 18, + Impale: 19, + Lightning_Bolt: 20, + Ice_Arrow: 21, + Guided_Arrow: 22, + Penetrate: 23, + Charged_Strike: 24, + Plague_Javelin: 25, + Strafe: 26, + Immolation_Arrow: 27, + Dopplezon: 28, + Evade: 29, + Fend: 30, + Freezing_Arrow: 31, + Valkyrie: 32, + Pierce: 33, + Lightning_Strike: 34, + Lightning_Fury: 35 + }, + Sorceress: { + Fire_Bolt: 36, + Warmth: 37, + Charged_Bolt: 38, + Ice_Bolt: 39, + Frozen_Armor: 40, + Inferno: 41, + Static_Field: 42, + Telekinesis: 43, + Frost_Nova: 44, + Ice_Blast: 45, + Blaze: 46, + Fire_Ball: 47, + Nova: 48, + Lightning: 49, + Shiver_Armor: 50, + Fire_Wall: 51, + Enchant: 52, + Chain_Lightning: 53, + Teleport: 54, + Glacial_Spike: 55, + Meteor: 56, + Thunder_Storm: 57, + Energy_Shield: 58, + Blizzard: 59, + Chilling_Armor: 60, + Fire_Mastery: 61, + Hydra: 62, + Lightning_Mastery: 63, + Frozen_Orb: 64, + Cold_Mastery: 65 + }, + Necromancer: { + Amplify_Damage: 66, + Teeth: 67, + Bone_Armor: 68, + Skeleton_Mastery: 69, + Raise_Skeleton: 70, + Dim_Vision: 71, + Weaken: 72, + Poison_Dagger: 73, + Corpse_Explosion: 74, + Clay_Golem: 75, + Iron_Maiden: 76, + Terror: 77, + Bone_Wall: 78, + Golem_Mastery: 79, + Raise_Skeletal_Mage: 80, + Confuse: 81, + Life_Tap: 82, + Poison_Explosion: 83, + Bone_Spear: 84, + BloodGolem: 85, + Attract: 86, + Decrepify: 87, + Bone_Prison: 88, + Summon_Resist: 89, + IronGolem: 90, + Lower_Resist: 91, + Poison_Nova: 92, + Bone_Spirit: 93, + FireGolem: 94, + Revive: 95 + }, + Paladin: { + Sacrifice: 96, + Smite: 97, + Might: 98, + Prayer: 99, + Resist_Fire: 100, + Holy_Bolt: 101, + Holy_Fire: 102, + Thorns: 103, + Defiance: 104, + Resist_Cold: 105, + Zeal: 106, + Charge: 107, + Blessed_Aim: 108, + Cleansing: 109, + Resist_Lightning: 110, + Vengeance: 111, + Blessed_Hammer: 112, + Concentration: 113, + Holy_Freeze: 114, + Vigor: 115, + Conversion: 116, + Holy_Shield: 117, + Holy_Shock: 118, + Sanctuary: 119, + Meditation: 120, + Fist_of_the_Heavens: 121, + Fanaticism: 122, + Conviction: 123, + Redemption: 124, + Salvation: 125 + }, + Barbarian: { + Bash: 126, + Sword_Mastery: 127, + Axe_Mastery: 128, + Mace_Mastery: 129, + Howl: 130, + Find_Potion: 131, + Leap: 132, + Double_Swing: 133, + Pole_Arm_Mastery: 134, + Throwing_Mastery: 135, + Spear_Mastery: 136, + Taunt: 137, + Shout: 138, + Stun: 139, + Double_Throw: 140, + Increased_Stamina: 141, + Find_Item: 142, + Leap_Attack: 143, + Concentrate: 144, + Iron_Skin: 145, + Battle_Cry: 146, + Frenzy: 147, + Increased_Speed: 148, + Battle_Orders: 149, + Grim_Ward: 150, + Whirlwind: 151, + Berserk: 152, + Natural_Resistance: 153, + War_Cry: 154, + Battle_Command: 155 + }, + Druid: { + Raven: 221, + Plague_Poppy: 222, + Wearwolf: 223, + Shape_Shifting: 224, + Firestorm: 225, + Oak_Sage: 226, + Summon_Spirit_Wolf: 227, + Wearbear: 228, + Molten_Boulder: 229, + Arctic_Blast: 230, + Cycle_of_Life: 231, + Feral_Rage: 232, + Maul: 233, + Eruption: 234, + Cyclone_Armor: 235, + Heart_of_Wolverine: 236, + Summon_Fenris: 237, + Rabies: 238, + Fire_Claws: 239, + Twister: 240, + Vines: 241, + Hunger: 242, + Shock_Wave: 243, + Volcano: 244, + Tornado: 245, + Spirit_of_Barbs: 246, + Summon_Grizzly: 247, + Fury: 248, + Armageddon: 249, + Hurricane: 250 + }, + Assassin: { + Fire_Trauma: 251, + Claw_Mastery: 252, + Psychic_Hammer: 253, + Tiger_Strike: 254, + Dragon_Talon: 255, + Shock_Field: 256, + Blade_Sentinel: 257, + Quickness: 258, + Fists_of_Fire: 259, + Dragon_Claw: 260, + Charged_Bolt_Sentry: 261, + Wake_of_Fire_Sentry: 262, + Weapon_Block: 263, + Cloak_of_Shadows: 264, + Cobra_Strike: 265, + Blade_Fury: 266, + Fade: 267, + Shadow_Warrior: 268, + Claws_of_Thunder: 269, + Dragon_Tail: 270, + Lightning_Sentry: 271, + Inferno_Sentry: 272, + Mind_Blast: 273, + Blades_of_Ice: 274, + Dragon_Flight: 275, + Death_Sentry: 276, + Blade_Shield: 277, + Venom: 278, + Shadow_Master: 279, + Royal_Strike: 280 + }, + Monsters: { + Fire_Hit: 156, + UnHolyBolt: 157, + SkeletonRaise: 158, + MaggotEgg: 159, + ShamanFire: 160, + MagottUp: 161, + MagottDown: 162, + MagottLay: 163, + AndrialSpray: 164, + Jump: 165, + Swarm_Move: 166, + Nest: 167, + Quick_Strike: 168, + VampireFireball: 169, + VampireFirewall: 170, + VampireMeteor: 171, + GargoyleTrap: 172, + SpiderLay: 173, + VampireHeal: 174, + VampireRaise: 175, + Submerge: 176, + FetishAura: 177, + FetishInferno: 178, + ZakarumHeal: 179, + Emerge: 180, + Resurrect: 181, + Bestow: 182, + MissileSkill1: 183, + MonTeleport: 184, + PrimeLightning: 185, + PrimeBolt: 186, + PrimeBlaze: 187, + PrimeFirewall: 188, + PrimeSpike: 189, + PrimeIceNova: 190, + PrimePoisonball: 191, + PrimePoisonNova: 192, + DiabLight: 193, + DiabCold: 194, + DiabFire: 195, + FingerMageSpider: 196, + DiabWall: 197, + DiabRun: 198, + DiabPrison: 199, + PoisonBallTrap: 200, + AndyPoisonBolt: 201, + HireableMissile: 202, + DesertTurret: 203, + ArcaneTower: 204, + MonBlizzard: 205, + Mosquito: 206, + CursedBallTrapRight: 207, + CursedBallTrapLeft: 208, + MonFrozenArmor: 209, + MonBoneArmor: 210, + MonBoneSpirit: 211, + MonCurseCast: 212, + HellMeteor: 213, + RegurgitatorEat: 214, + MonFrenzy: 215, + QueenDeath: 216, + Wake_Of_Destruction_Sentry: 281, + Imp_Inferno: 282, + Imp_Fireball: 283, + Baal_Taunt: 284, + Baal_Corpse_Explode: 285, + Baal_Monster_Spawn: 286, + Catapult_Charged_Ball: 287, + Catapult_Spike_Ball: 288, + Suck_Blood: 289, + Cry_Help: 290, + Healing_Vortex: 291, + Teleport_2: 292, + Self_resurrect: 293, + Vine_Attack: 294, + Overseer_Whip: 295, + Barbs_Aura: 296, + Wolverine_Aura: 297, + Oak_Sage_Aura: 298, + Imp_Fire_Missile: 299, + Impregnate: 300, + Siege_Beast_Stomp: 301, + MinionSpawner: 302, + CatapultBlizzard: 303, + CatapultPlague: 304, + CatapultMeteor: 305, + BoltSentry: 306, + CorpseCycler: 307, + DeathMaul: 308, + Defense_Curse: 309, + Blood_Mana: 310, + mon_inferno_sentry: 311, + mon_death_sentry: 312, + sentry_lightning: 313, + fenris_rage: 314, + Baal_Tentacle: 315, + Baal_Nova: 316, + Baal_Inferno: 317, + Baal_Cold_Missiles: 318, + MegademonInferno: 319, + EvilHutSpawner: 320, + CountessFirewall: 321, + ImpBolt: 322, + Horror_Arctic_Blast: 323, + death_sentry_ltngv: 324, + VineCycler: 325, + BearSmite: 326, + Resurrect2: 327, + BloodLordFrenzy: 328, + Baal_Teleport: 329, + Imp_Teleport: 330, + Baal_Clone_Teleport: 331, + ZakarumLightning: 332, + VampireMissile: 333, + MephistoMissile: 334, + DoomKnightMissile: 335, + RogueMissile: 336, + HydraMissile: 337, + NecromageMissile: 338, + MonBow: 339, + MonFireArrow: 340, + MonColdArrow: 341, + MonExplodingArrow: 342, + MonFreezingArrow: 343, + MonPowerStrike: 344, + SuccubusBolt: 345, + MephFrostNova: 346, + MonIceSpear: 347, + ShamanIce: 348, + Diablogeddon: 349, + Delerium_Change: 350, + NihlathakCorpseExplosion: 351, + SerpentCharge: 352, + Trap_Nova: 353, + UnHolyBoltEx: 354, + ShamanFireEx: 355, + Imp_Fire_Missile_Ex: 356 + } + }; + + var Areas = { + None: 0, + Act1: { + Rogue_Encampment: 1, + Blood_Moor: 2, + Cold_Plains: 3, + Stony_Field: 4, + Dark_Wood: 5, + Black_Marsh: 6, + Tamoe_Highland: 7, + Den_Of_Evil: 8, + Cave_Level_1: 9, + Underground_Passage_Level_1: 10, + Hole_Level_1: 11, + Pit_Level_1: 12, + Cave_Level_2: 13, + Underground_Passage_Level_2: 14, + Hole_Level_2: 15, + Pit_Level_2: 16, + Burial_Grounds: 17, + Crypt: 18, + Mausoleum: 19, + Forgotten_Tower: 20, + Tower_Cellar_Level_1: 21, + Tower_Cellar_Level_2: 22, + Tower_Cellar_Level_3: 23, + Tower_Cellar_Level_4: 24, + Tower_Cellar_Level_5: 25, + Monastery_Gate: 26, + Outer_Cloister: 27, + Barracks: 28, + Jail_Level_1: 29, + Jail_Level_2: 30, + Jail_Level_3: 31, + Inner_Cloister: 32, + Cathedral: 33, + Catacombs_Level_1: 34, + Catacombs_Level_2: 35, + Catacombs_Level_3: 36, + Catacombs_Level_4: 37, + Tristram: 38, + Moo_Moo_Farm: 39 + }, + Act2: { + Lut_Gholein: 40, + Rocky_Waste: 41, + Dry_Hills: 42, + Far_Oasis: 43, + Lost_City: 44, + Valley_Of_Snakes: 45, + Canyon_Of_The_Magi: 46, + A2_Sewers_Level_1: 47, + A2_Sewers_Level_2: 48, + A2_Sewers_Level_3: 49, + Harem_Level_1: 50, + Harem_Level_2: 51, + Palace_Cellar_Level_1: 52, + Palace_Cellar_Level_2: 53, + Palace_Cellar_Level_3: 54, + Stony_Tomb_Level_1: 55, + Halls_Of_The_Dead_Level_1: 56, + Halls_Of_The_Dead_Level_2: 57, + Claw_Viper_Temple_Level_1: 58, + Stony_Tomb_Level_2: 59, + Halls_Of_The_Dead_Level_3: 60, + Claw_Viper_Temple_Level_2: 61, + Maggot_Lair_Level_1: 62, + Maggot_Lair_Level_2: 63, + Maggot_Lair_Level_3: 64, + Ancient_Tunnels: 65, + Tal_Rashas_Tomb_1: 66, + Tal_Rashas_Tomb_2: 67, + Tal_Rashas_Tomb_3: 68, + Tal_Rashas_Tomb_4: 69, + Tal_Rashas_Tomb_5: 70, + Tal_Rashas_Tomb_6: 71, + Tal_Rashas_Tomb_7: 72, + Duriels_Lair: 73, + Arcane_Sanctuary: 74 + }, + Act3: { + Kurast_Docktown: 75, + Spider_Forest: 76, + Great_Marsh: 77, + Flayer_Jungle: 78, + Lower_Kurast: 79, + Kurast_Bazaar: 80, + Upper_Kurast: 81, + Kurast_Causeway: 82, + Travincal: 83, + Spider_Cave: 84, + Spider_Cavern: 85, + Swampy_Pit_Level_1: 86, + Swampy_Pit_Level_2: 87, + Flayer_Dungeon_Level_1: 88, + Flayer_Dungeon_Level_2: 89, + Swampy_Pit_Level_3: 90, + Flayer_Dungeon_Level_3: 91, + A3_Sewers_Level_1: 92, + A3_Sewers_Level_2: 93, + Ruined_Temple: 94, + Disused_Fane: 95, + Forgotten_Reliquary: 96, + Forgotten_Temple: 97, + Ruined_Fane: 98, + Disused_Reliquary: 99, + Durance_Of_Hate_Level_1: 100, + Durance_Of_Hate_Level_2: 101, + Durance_Of_Hate_Level_3: 102 + }, + Act4: { + The_Pandemonium_Fortress: 103, + Outer_Steppes: 104, + Plains_Of_Despair: 105, + City_Of_The_Damned: 106, + River_Of_Flame: 107, + Chaos_Sanctuary: 108 + }, + Act5: { + Harrogath: 109, + Bloody_Foothills: 110, + Frigid_Highlands: 111, + Arreat_Plateau: 112, + Crystalized_Passage: 113, + Frozen_River: 114, + Glacial_Trail: 115, + Drifter_Cavern: 116, + Frozen_Tundra: 117, + Ancients_Way: 118, + Icy_Cellar: 119, + Arreat_Summit: 120, + Nihlathaks_Temple: 121, + Halls_Of_Anguish: 122, + Halls_Of_Pain: 123, + Halls_Of_Vaught: 124, + Abaddon: 125, + Pit_Of_Acheron: 126, + Infernal_Pit: 127, + The_Worldstone_Keep_Level_1: 128, + The_Worldstone_Keep_Level_2: 129, + The_Worldstone_Keep_Level_3: 130, + Throne_Of_Destruction: 131, + The_Worldstone_Chamber: 132 + }, + UberLevels: { + Matrons_Den: 133, + Fogotten_Sands: 134, + Furnace_of_Pain: 135, + Tristram: 136 + } + }; + + var NPCMenu = { + Talk: 0x0D35, + Trade: 0x0D44, + Trade_Repair: 0x0D06, + Imbue: 0x0FB1, + Gamble: 0x0D46, + Hire: 0x0D45, + Go_East: 0x0D36, + Go_West: 0x0D37, + Identify_Items: 0x0FB4, + Sail_East: 0x0D38, + Sail_West: 0x0D39, + Ressurect_Merc: 0x1507, + Add_Sockets: 0x58DC, + Personalize: 0x58DD, + Travel_to_Harrogath: 0x58D2 + }; + + var GameType = { + Classic: 0, + Expansion: 1 + }; + + var NPCModes = { + death: 0, + neutral: 1, + walk: 2, + gethit: 3, + attack1: 4, + attack2: 5, + block: 6, + cast: 7, + skill1: 8, + skill2: 9, + skill3: 10, + skill4: 11, + dead: 12, + knockback: 13, + sequence: 14, + run: 15 + }; + + var PlayerModes = { + Death: 0, + Neutral: 1, + Walk: 2, + Run: 3, + Get_Hit: 4, + Town_Neutral: 5, + Town_Walk: 6, + Attack1: 7, + Attack2: 8, + Block: 9, + Cast: 10, + Throw: 11, + Kick: 12, + Skill1: 13, + Skill2: 14, + Skill3: 15, + Skill4: 16, + Dead: 17, + Sequence: 18, + Knockback: 19 + }; + + var ObjectModes = { + Neutral: 0, + Operating: 1, + Opened: 2, + Special1: 3, + Special2: 4, + Special3: 5, + Special4: 6, + Special5: 7 + }; + + var ItemModes = { + Item_In_Inventory_Stash_Cube_Or_Store: 0, + Item_equipped_self_or_merc: 1, + Item_in_belt: 2, + Item_on_ground: 3, + Item_on_cursor: 4, + Item_being_dropped: 5, + Item_socketed_in_item: 6 + }; + + /* QuestCompletion + 0 = Requirements Complete (Quest Complete) + 2 = Quest Started + 3-10 = Parts of Quest Complete Varies by Quest + 12 = Quest Box Filled in + */ + var Quests = { + Act1: { + Spoke_to_Warriv: 0, + Den_of_Evil: 1, + Sisters_Burial_Grounds: 2, + The_Search_for_Cain: 4, + Forgotten_Tower: 5, + Tools_of_the_Trade: 3, + Sisters_to_the_Slaughter: 6, + Able_to_go_to_Act_II: 7 + }, + Act2: { + Spoke_to_Jerhyn: 8, + Radaments_Lair: 9, + The_Horadric_Staff: 10, + The_Tainted_Sun: 11, + The_Arcane_Sanctuary: 12, + The_Summoner: 13, + The_Seven_Tombs: 14, + Able_to_go_to_Act_III: 15 + }, + Act3: { + Spoke_to_Hratli: 16, + The_Golden_Bird: 20, + Blade_of_the_Old_Religion: 19, + Khalims_Will: 18, + Lam_Esens_Tome: 17, + The_Blackened_Temple: 21, + The_Guardian: 22, + Able_to_go_to_Act_IV: 23 + }, + Act4: { + Spoke_to_Tyrael: 24, + The_Fallen_Angel: 25, + Hells_Forge: 27, + Terrors_End: 26, + Able_to_go_to_Act_V: 28 + }, + Act5: { + Seige_on_Haggorath: 35, + Rescue_on_Mount_Arreat: 36, + Prison_of_Ice: 37, + Betrayal_of_Haggorath: 38, + Rite_of_Passage: 39, + Eve_of_Destruction: 40 + } + }; + + var Shrines = { + null: 0, + refilling: 1, + health: 2, + mana: 3, + health_exchange: 4, + mana_exchange: 5, + armor: 6, + combat: 7, + resist_fire: 8, + resist_cold: 9, + resist_lightning: 10, + resist_poison: 11, + skill: 12, + mana_recharge: 13, + stamina: 14, + experience: 15, + enirhs: 16, + portal: 17, + gem: 18, + fire: 19, + monster: 20, + exploding: 21, + poison: 22 + }; + + var Stats = { + strength: 0, + energy: 1, + dexterity: 2, + vitality: 3, + statpts: 4, + newskills: 5, + hitpoints: 6, + maxhp: 7, + mana: 8, + maxmana: 9, + stamina: 10, + maxstamina: 11, + level: 12, + experience: 13, + gold: 14, + goldbank: 15, + item_armor_percent: 16, + item_maxdamage_percent: 17, + item_mindamage_percent: 18, + tohit: 19, + toblock: 20, + mindamage: 21, + maxdamage: 22, + secondary_mindamage: 23, + secondary_maxdamage: 24, + damagepercent: 25, + manarecovery: 26, + manarecoverybonus: 27, + staminarecoverybonus: 28, + lastexp: 29, + nextexp: 30, + armorclass: 31, + armorclass_vs_missile: 32, + armorclass_vs_hth: 33, + normal_damage_reduction: 34, + magic_damage_reduction: 35, + damageresist: 36, + magicresist: 37, + maxmagicresist: 38, + fireresist: 39, + maxfireresist: 40, + lightresist: 41, + maxlightresist: 42, + coldresist: 43, + maxcoldresist: 44, + poisonresist: 45, + maxpoisonresist: 46, + damageaura: 47, + firemindam: 48, + firemaxdam: 49, + lightmindam: 50, + lightmaxdam: 51, + magicmindam: 52, + magicmaxdam: 53, + coldmindam: 54, + coldmaxdam: 55, + coldlength: 56, + poisonmindam: 57, + poisonmaxdam: 58, + poisonlength: 59, + lifedrainmindam: 60, + lifedrainmaxdam: 61, + manadrainmindam: 62, + manadrainmaxdam: 63, + stamdrainmindam: 64, + stamdrainmaxdam: 65, + stunlength: 66, + velocitypercent: 67, + attackrate: 68, + other_animrate: 69, + quantity: 70, + value: 71, + durability: 72, + maxdurability: 73, + hpregen: 74, + item_maxdurability_percent: 75, + item_maxhp_percent: 76, + item_maxmana_percent: 77, + item_attackertakesdamage: 78, + item_goldbonus: 79, + item_magicbonus: 80, + item_knockback: 81, + item_timeduration: 82, + item_addclassskills: 83, + unsentparam1: 84, + item_addexperience: 85, + item_healafterkill: 86, + item_reducedprices: 87, + item_doubleherbduration: 88, + item_lightradius: 89, + item_lightcolor: 90, + item_req_percent: 91, + item_levelreq: 92, + item_fasterattackrate: 93, + item_levelreqpct: 94, + lastblockframe: 95, + item_fastermovevelocity: 96, + item_nonclassskill: 97, + state: 98, + item_fastergethitrate: 99, + monster_playercount: 100, + skill_poison_override_length: 101, + item_fasterblockrate: 102, + skill_bypass_undead: 103, + skill_bypass_demons: 104, + item_fastercastrate: 105, + skill_bypass_beasts: 106, + item_singleskill: 107, + item_restinpeace: 108, + curse_resistance: 109, + item_poisonlengthresist: 110, + item_normaldamage: 111, + item_howl: 112, + item_stupidity: 113, + item_damagetomana: 114, + item_ignoretargetac: 115, + item_fractionaltargetac: 116, + item_preventheal: 117, + item_halffreezeduration: 118, + item_tohit_percent: 119, + item_damagetargetac: 120, + item_demondamage_percent: 121, + item_undeaddamage_percent: 122, + item_demon_tohit: 123, + item_undead_tohit: 124, + item_throwable: 125, + item_elemskill: 126, + item_allskills: 127, + item_attackertakeslightdamage: 128, + ironmaiden_level: 129, + lifetap_level: 130, + thorns_percent: 131, + bonearmor: 132, + bonearmormax: 133, + item_freeze: 134, + item_openwounds: 135, + item_crushingblow: 136, + item_kickdamage: 137, + item_manaafterkill: 138, + item_healafterdemonkill: 139, + item_extrablood: 140, + item_deadlystrike: 141, + item_absorbfire_percent: 142, + item_absorbfire: 143, + item_absorblight_percent: 144, + item_absorblight: 145, + item_absorbmagic_percent: 146, + item_absorbmagic: 147, + item_absorbcold_percent: 148, + item_absorbcold: 149, + item_slow: 150, + item_aura: 151, + item_indesctructible: 152, + item_cannotbefrozen: 153, + item_staminadrainpct: 154, + item_reanimate: 155, + item_pierce: 156, + item_magicarrow: 157, + item_explosivearrow: 158, + item_throw_mindamage: 159, + item_throw_maxdamage: 160, + skill_handofathena: 161, + skill_staminapercent: 162, + skill_passive_staminapercent: 163, + skill_concentration: 164, + skill_enchant: 165, + skill_pierce: 166, + skill_conviction: 167, + skill_chillingarmor: 168, + skill_frenzy: 169, + skill_decrepify: 170, + skill_armor_percent: 171, + alignment: 172, + target0: 173, + target1: 174, + goldlost: 175, + conversion_level: 176, + conversion_maxhp: 177, + unit_dooverlay: 178, + attack_vs_montype: 179, + damage_vs_montype: 180, + fade: 181, + armor_override_percent: 182, + unused183: 183, + unused184: 184, + unused185: 185, + unused186: 186, + unused187: 187, + item_addskill_tab: 188, + unused189: 189, + unused190: 190, + unused191: 191, + unused192: 192, + unused193: 193, + item_numsockets: 194, + item_skillonattack: 195, + item_skillonkill: 196, + item_skillondeath: 197, + item_skillonhit: 198, + item_skillonlevelup: 199, + unused200: 200, + item_skillongethit: 201, + unused202: 202, + unused203: 203, + item_charged_skill: 204, + unused204: 205, + unused205: 206, + unused206: 207, + unused207: 208, + unused208: 209, + unused209: 210, + unused210: 211, + unused211: 212, + unused212: 213, + item_armor_perlevel: 214, + item_armorpercent_perlevel: 215, + item_hp_perlevel: 216, + item_mana_perlevel: 217, + item_maxdamage_perlevel: 218, + item_maxdamage_percent_perlevel: 219, + item_strength_perlevel: 220, + item_dexterity_perlevel: 221, + item_energy_perlevel: 222, + item_vitality_perlevel: 223, + item_tohit_perlevel: 224, + item_tohitpercent_perlevel: 225, + item_cold_damagemax_perlevel: 226, + item_fire_damagemax_perlevel: 227, + item_ltng_damagemax_perlevel: 228, + item_pois_damagemax_perlevel: 229, + item_resist_cold_perlevel: 230, + item_resist_fire_perlevel: 231, + item_resist_ltng_perlevel: 232, + item_resist_pois_perlevel: 233, + item_absorb_cold_perlevel: 234, + item_absorb_fire_perlevel: 235, + item_absorb_ltng_perlevel: 236, + item_absorb_pois_perlevel: 237, + item_thorns_perlevel: 238, + item_find_gold_perlevel: 239, + item_find_magic_perlevel: 240, + item_regenstamina_perlevel: 241, + item_stamina_perlevel: 242, + item_damage_demon_perlevel: 243, + item_damage_undead_perlevel: 244, + item_tohit_demon_perlevel: 245, + item_tohit_undead_perlevel: 246, + item_crushingblow_perlevel: 247, + item_openwounds_perlevel: 248, + item_kick_damage_perlevel: 249, + item_deadlystrike_perlevel: 250, + item_find_gems_perlevel: 251, + item_replenish_durability: 252, + item_replenish_quantity: 253, + item_extra_stack: 254, + item_find_item: 255, + item_slash_damage: 256, + item_slash_damage_percent: 257, + item_crush_damage: 258, + item_crush_damage_percent: 259, + item_thrust_damage: 260, + item_thrust_damage_percent: 261, + item_absorb_slash: 262, + item_absorb_crush: 263, + item_absorb_thrust: 264, + item_absorb_slash_percent: 265, + item_absorb_crush_percent: 266, + item_absorb_thrust_percent: 267, + item_armor_bytime: 268, + item_armorpercent_bytime: 269, + item_hp_bytime: 270, + item_mana_bytime: 271, + item_maxdamage_bytime: 272, + item_maxdamage_percent_bytime: 273, + item_strength_bytime: 274, + item_dexterity_bytime: 275, + item_energy_bytime: 276, + item_vitality_bytime: 277, + item_tohit_bytime: 278, + item_tohitpercent_bytime: 279, + item_cold_damagemax_bytime: 280, + item_fire_damagemax_bytime: 281, + item_ltng_damagemax_bytime: 282, + item_pois_damagemax_bytime: 283, + item_resist_cold_bytime: 284, + item_resist_fire_bytime: 285, + item_resist_ltng_bytime: 286, + item_resist_pois_bytime: 287, + item_absorb_cold_bytime: 288, + item_absorb_fire_bytime: 289, + item_absorb_ltng_bytime: 290, + item_absorb_pois_bytime: 291, + item_find_gold_bytime: 292, + item_find_magic_bytime: 293, + item_regenstamina_bytime: 294, + item_stamina_bytime: 295, + item_damage_demon_bytime: 296, + item_damage_undead_bytime: 297, + item_tohit_demon_bytime: 298, + item_tohit_undead_bytime: 299, + item_crushingblow_bytime: 300, + item_openwounds_bytime: 301, + item_kick_damage_bytime: 302, + item_deadlystrike_bytime: 303, + item_find_gems_bytime: 304, + item_pierce_cold: 305, + item_pierce_fire: 306, + item_pierce_ltng: 307, + item_pierce_pois: 308, + item_damage_vs_monster: 309, + item_damage_percent_vs_monster: 310, + item_tohit_vs_monster: 311, + item_tohit_percent_vs_monster: 312, + item_ac_vs_monster: 313, + item_ac_percent_vs_monster: 314, + firelength: 315, + burningmin: 316, + burningmax: 317, + progressive_damage: 318, + progressive_steal: 319, + progressive_other: 320, + progressive_fire: 321, + progressive_cold: 322, + progressive_lightning: 323, + item_extra_charges: 324, + progressive_tohit: 325, + poison_count: 326, + damage_framerate: 327, + pierce_idx: 328, + passive_fire_mastery: 329, + passive_ltng_mastery: 330, + passive_cold_mastery: 331, + passive_pois_mastery: 332, + passive_fire_pierce: 333, + passive_ltng_pierce: 334, + passive_cold_pierce: 335, + passive_pois_pierce: 336, + passive_critical_strike: 337, + passive_dodge: 338, + passive_avoid: 339, + passive_evade: 340, + passive_warmth: 341, + passive_mastery_melee_th: 342, + passive_mastery_melee_dmg: 343, + passive_mastery_melee_crit: 344, + passive_mastery_throw_th: 345, + passive_mastery_throw_dmg: 346, + passive_mastery_throw_crit: 347, + passive_weaponblock: 348, + passive_summon_resist: 349, + modifierlist_skill: 350, + modifierlist_level: 351, + last_sent_hp_pct: 352, + source_unit_type: 353, + source_unit_id: 354, + shortparam1: 355, + questitemdifficulty: 356, + passive_mag_mastery: 357, + passive_mag_pierce: 358 + }; + + var stats_Skills = { + Attack: 0, + Kick: 1, + Throw: 2, + Unsummon: 3, + Left_Hand_Throw: 4, + Left_Hand_Swing: 5, + Magic_Arrow: 6, + Fire_Arrow: 7, + Inner_Sight: 8, + Critical_Strike: 9, + Jab: 10, + Cold_Arrow: 11, + Multiple_Shot: 12, + Dodge: 13, + Power_Strike: 14, + Poison_Javelin: 15, + Exploding_Arrow: 16, + Slow_Missiles: 17, + Avoid: 18, + Impale: 19, + Lightning_Bolt: 20, + Ice_Arrow: 21, + Guided_Arrow: 22, + Penetrate: 23, + Charged_Strike: 24, + Plague_Javelin: 25, + Strafe: 26, + Immolation_Arrow: 27, + Dopplezon: 28, + Evade: 29, + Fend: 30, + Freezing_Arrow: 31, + Valkyrie: 32, + Pierce: 33, + Lightning_Strike: 34, + Lightning_Fury: 35, + Fire_Bolt: 36, + Warmth: 37, + Charged_Bolt: 38, + Ice_Bolt: 39, + Frozen_Armor: 40, + Inferno: 41, + Static_Field: 42, + Telekinesis: 43, + Frost_Nova: 44, + Ice_Blast: 45, + Blaze: 46, + Fire_Ball: 47, + Nova: 48, + Lightning: 49, + Shiver_Armor: 50, + Fire_Wall: 51, + Enchant: 52, + Chain_Lightning: 53, + Teleport: 54, + Glacial_Spike: 55, + Meteor: 56, + Thunder_Storm: 57, + Energy_Shield: 58, + Blizzard: 59, + Chilling_Armor: 60, + Fire_Mastery: 61, + Hydra: 62, + Lightning_Mastery: 63, + Frozen_Orb: 64, + Cold_Mastery: 65, + Amplify_Damage: 66, + Teeth: 67, + Bone_Armor: 68, + Skeleton_Mastery: 69, + Raise_Skeleton: 70, + Dim_Vision: 71, + Weaken: 72, + Poison_Dagger: 73, + Corpse_Explosion: 74, + Clay_Golem: 75, + Iron_Maiden: 76, + Terror: 77, + Bone_Wall: 78, + Golem_Mastery: 79, + Raise_Skeletal_Mage: 80, + Confuse: 81, + Life_Tap: 82, + Poison_Explosion: 83, + Bone_Spear: 84, + BloodGolem: 85, + Attract: 86, + Decrepify: 87, + Bone_Prison: 88, + Summon_Resist: 89, + IronGolem: 90, + Lower_Resist: 91, + Poison_Nova: 92, + Bone_Spirit: 93, + FireGolem: 94, + Revive: 95, + Sacrifice: 96, + Smite: 97, + Might: 98, + Prayer: 99, + Resist_Fire: 100, + Holy_Bolt: 101, + Holy_Fire: 102, + Thorns: 103, + Defiance: 104, + Resist_Cold: 105, + Zeal: 106, + Charge: 107, + Blessed_Aim: 108, + Cleansing: 109, + Resist_Lightning: 110, + Vengeance: 111, + Blessed_Hammer: 112, + Concentration: 113, + Holy_Freeze: 114, + Vigor: 115, + Conversion: 116, + Holy_Shield: 117, + Holy_Shock: 118, + Sanctuary: 119, + Meditation: 120, + Fist_of_the_Heavens: 121, + Fanaticism: 122, + Conviction: 123, + Redemption: 124, + Salvation: 125, + Bash: 126, + Sword_Mastery: 127, + Axe_Mastery: 128, + Mace_Mastery: 129, + Howl: 130, + Find_Potion: 131, + Leap: 132, + Double_Swing: 133, + Pole_Arm_Mastery: 134, + Throwing_Mastery: 135, + Spear_Mastery: 136, + Taunt: 137, + Shout: 138, + Stun: 139, + Double_Throw: 140, + Increased_Stamina: 141, + Find_Item: 142, + Leap_Attack: 143, + Concentrate: 144, + Iron_Skin: 145, + Battle_Cry: 146, + Frenzy: 147, + Increased_Speed: 148, + Battle_Orders: 149, + Grim_Ward: 150, + Whirlwind: 151, + Berserk: 152, + Natural_Resistance: 153, + War_Cry: 154, + Battle_Command: 155, + Fire_Hit: 156, + UnHolyBolt: 157, + SkeletonRaise: 158, + MaggotEgg: 159, + ShamanFire: 160, + MagottUp: 161, + MagottDown: 162, + MagottLay: 163, + AndrialSpray: 164, + Jump: 165, + Swarm_Move: 166, + Nest: 167, + Quick_Strike: 168, + VampireFireball: 169, + VampireFirewall: 170, + VampireMeteor: 171, + GargoyleTrap: 172, + SpiderLay: 173, + VampireHeal: 174, + VampireRaise: 175, + Submerge: 176, + FetishAura: 177, + FetishInferno: 178, + ZakarumHeal: 179, + Emerge: 180, + Resurrect: 181, + Bestow: 182, + MissileSkill1: 183, + MonTeleport: 184, + PrimeLightning: 185, + PrimeBolt: 186, + PrimeBlaze: 187, + PrimeFirewall: 188, + PrimeSpike: 189, + PrimeIceNova: 190, + PrimePoisonball: 191, + PrimePoisonNova: 192, + DiabLight: 193, + DiabCold: 194, + DiabFire: 195, + FingerMageSpider: 196, + DiabWall: 197, + DiabRun: 198, + DiabPrison: 199, + PoisonBallTrap: 200, + AndyPoisonBolt: 201, + HireableMissile: 202, + DesertTurret: 203, + ArcaneTower: 204, + MonBlizzard: 205, + Mosquito: 206, + CursedBallTrapRight: 207, + CursedBallTrapLeft: 208, + MonFrozenArmor: 209, + MonBoneArmor: 210, + MonBoneSpirit: 211, + MonCurseCast: 212, + HellMeteor: 213, + RegurgitatorEat: 214, + MonFrenzy: 215, + QueenDeath: 216, + Scroll_of_Identify: 217, + Book_of_Identify: 218, + Scroll_of_Townportal: 219, + Book_of_Townportal: 220, + Raven: 221, + Plague_Poppy: 222, + Wearwolf: 223, + Shape_Shifting: 224, + Firestorm: 225, + Oak_Sage: 226, + Summon_Spirit_Wolf: 227, + Wearbear: 228, + Molten_Boulder: 229, + Arctic_Blast: 230, + Cycle_of_Life: 231, + Feral_Rage: 232, + Maul: 233, + Eruption: 234, + Cyclone_Armor: 235, + Heart_of_Wolverine: 236, + Summon_Fenris: 237, + Rabies: 238, + Fire_Claws: 239, + Twister: 240, + Vines: 241, + Hunger: 242, + Shock_Wave: 243, + Volcano: 244, + Tornado: 245, + Spirit_of_Barbs: 246, + Summon_Grizzly: 247, + Fury: 248, + Armageddon: 249, + Hurricane: 250, + Fire_Trauma: 251, + Claw_Mastery: 252, + Psychic_Hammer: 253, + Tiger_Strike: 254, + Dragon_Talon: 255, + Shock_Field: 256, + Blade_Sentinel: 257, + Quickness: 258, + Fists_of_Fire: 259, + Dragon_Claw: 260, + Charged_Bolt_Sentry: 261, + Wake_of_Fire_Sentry: 262, + Weapon_Block: 263, + Cloak_of_Shadows: 264, + Cobra_Strike: 265, + Blade_Fury: 266, + Fade: 267, + Shadow_Warrior: 268, + Claws_of_Thunder: 269, + Dragon_Tail: 270, + Lightning_Sentry: 271, + Inferno_Sentry: 272, + Mind_Blast: 273, + Blades_of_Ice: 274, + Dragon_Flight: 275, + Death_Sentry: 276, + Blade_Shield: 277, + Venom: 278, + Shadow_Master: 279, + Royal_Strike: 280, + Wake_Of_Destruction_Sentry: 281, + Imp_Inferno: 282, + Imp_Fireball: 283, + Baal_Taunt: 284, + Baal_Corpse_Explode: 285, + Baal_Monster_Spawn: 286, + Catapult_Charged_Ball: 287, + Catapult_Spike_Ball: 288, + Suck_Blood: 289, + Cry_Help: 290, + Healing_Vortex: 291, + Teleport_2: 292, + Self_resurrect: 293, + Vine_Attack: 294, + Overseer_Whip: 295, + Barbs_Aura: 296, + Wolverine_Aura: 297, + Oak_Sage_Aura: 298, + Imp_Fire_Missile: 299, + Impregnate: 300, + Siege_Beast_Stomp: 301, + MinionSpawner: 302, + CatapultBlizzard: 303, + CatapultPlague: 304, + CatapultMeteor: 305, + BoltSentry: 306, + CorpseCycler: 307, + DeathMaul: 308, + Defense_Curse: 309, + Blood_Mana: 310, + mon_inferno_sentry: 311, + mon_death_sentry: 312, + sentry_lightning: 313, + fenris_rage: 314, + Baal_Tentacle: 315, + Baal_Nova: 316, + Baal_Inferno: 317, + Baal_Cold_Missiles: 318, + MegademonInferno: 319, + EvilHutSpawner: 320, + CountessFirewall: 321, + ImpBolt: 322, + Horror_Arctic_Blast: 323, + death_sentry_ltng: 324, + VineCycler: 325, + BearSmite: 326, + Resurrect2: 327, + BloodLordFrenzy: 328, + Baal_Teleport: 329, + Imp_Teleport: 330, + Baal_Clone_Teleport: 331, + ZakarumLightning: 332, + VampireMissile: 333, + MephistoMissile: 334, + DoomKnightMissile: 335, + RogueMissile: 336, + HydraMissile: 337, + NecromageMissile: 338, + MonBow: 339, + MonFireArrow: 340, + MonColdArrow: 341, + MonExplodingArrow: 342, + MonFreezingArrow: 343, + MonPowerStrike: 344, + SuccubusBolt: 345, + MephFrostNova: 346, + MonIceSpear: 347, + ShamanIce: 348, + Diablogeddon: 349, + Delerium_Change: 350, + NihlathakCorpseExplosion: 351, + SerpentCharge: 352, + Trap_Nova: 353, + UnHolyBoltEx: 354, + ShamanFireEx: 355, + Imp_Fire_Missile_Ex: 356 + }; + + //item.getStat( 188, tab ); // lookup table + //-- thanks to TheDesertWind for this list + var stats_tabs = { + Bow_and_Crossbow_Skills: 0, + Passive_and_Magic_Skills: 1, + Javelin_and_Spear_Skills: 2, + Fire_Skills: 8, + Lightning_Skills: 9, + Cold_Skills: 10, + Curses_Skills: 16, + Poison_and_Bone_Skills: 17, + Necromancer_Summoning_Skills: 18, + Paladin_Combat_Skills: 24, + Offensive_Auras_Skills: 25, + Defensive_Auras_Skills: 26, + Barbarian_Combat_Skills: 32, + Masteries_Skills: 33, + Warcries_Skills: 34, + Druid_Summoning_Skills: 40, + Shape_Shifting_Skills: 41, + Elemental_Skills: 42, + Traps_Skills: 48, + Shadow_Disciplines_Skills: 49, + Martial_Arts_Skills: 50 + }; + + var Superunique_PresetUnitIds = { + The_Summoner: 250, + Bishibosh: 704, + Bonebreak: 705, + Coldcrow: 706, + Rakanishu: 707, + Treehead_WoodFist: 708, + Griswold: 709, + The_Countess: 710, + Pitspawn_Fouldog: 711, + Flamespike_the_Crawler: 712, + Boneash: 713, + Radament: 714, + Bloodwitch_the_Wild: 715, + Fangskin: 716, + Beetleburst: 717, + Leatherarm: 718, + Coldworm_the_Burrower: 719, + Fire_Eye: 720, + Dark_Elder: 721, + Ancient_Kaa_the_Soulless: 723, + The_Smith: 724, + Web_Mage_the_Burning: 725, + Witch_Doctor_Endugu: 726, + Stormtree: 727, + Sarina_the_Battlemaid: 728, + Icehawk_Riftwing: 729, + Ismail_Vilehand: 730, + Geleb_Flamefinger: 731, + Bremm_Sparkfist: 732, + Toorc_Icefist: 733, + Wyand_Voidfinger: 734, + Maffer_Dragonhand: 735, + Winged_Death: 736, + The_Tormentor: 737, + Taintbreeder: 738, + Riftwraith_the_Cannibal: 739, + Infector_of_Souls: 740, + Lord_De_Seis: 741, + Grand_Vizier_of_Chaos: 742, + The_Cow_King: 743, + Corpsefire: 744, + Hephasto_The_Feature_Creep: 745, + Siege_Boss: 746, + Ancient_Barbarian_1: 747, + Ancient_Barbarian_2: 748, + Ancient_Barbarian_3: 749, + Axe_Dweller: 750, + Bonesaw_Breaker: 751, + Dac_Farren: 752, + Eldritch_Megaflow_Rectifier: 753, + Eyeback_Unleashed: 754, + Threash_Socket: 755, + Pindleskin: 756, + Snapchip_Shatter: 757, + Anodized_Elite: 758, + Vinvear_Molech: 759, + Sharp_Tooth_Sayer: 760, + Magma_Torquer: 761, + Blaze_Ripper: 762, + Frozenstein: 763, + Nihlathak_Boss: 764, + Baal_Subject_1: 765, + Baal_Subject_2: 766, + Baal_Subject_3: 767, + Baal_Subject_4: 768, + Baal_Subject_5: 769, + random_boss_pack: 772, + random_champ_pack: 773, + Flavie: 774, + Blood_Raven: 775, + maggot_queen_broken: 778, + tenticles: 780, + tenticles2: 781, + flayers: 787, + flayer_shaman: 788, + ratmen: 792, + ratmen_shaman: 793, + demonimp_pack: 794, + enslaved_pack: 796, + unknown1: 795, + unknown2: 797, + unknown3: 798, + dead_enslaved: 799, + dead_demonimp: 800, + dead_barb: 801, + dead_prowlingdead: 802 + }; + + var SuperUniques = { + Bishibosh: 734, + Bonebreak: 735, + Coldcrow: 736, + Rakanishu: 737, + Treehead_WoodFist: 738, + Griswold: 739, + The_Countess: 740, + Pitspawn_Fouldog: 741, + Flamespike_the_Crawler: 742, + Boneash: 743, + Radament: 744, + Bloodwitch_the_Wild: 745, + Fangskin: 746, + Beetleburst: 747, + Leatherarm: 748, + Coldworm_the_Burrower: 749, + Fire_Eye: 750, + Dark_Elder: 751, + The_Summoner: 752, + Ancient_Kaa_the_Soulless: 753, + The_Smith: 754, + Web_Mage_the_Burning: 755, + Witch_Doctor_Endugu: 756, + Stormtree: 757, + Sarina_the_Battlemaid: 758, + Icehawk_Riftwing: 759, + Ismail_Vilehand: 760, + Geleb_Flamefinger: 761, + Bremm_Sparkfist: 762, + Toorc_Icefist: 763, + Wyand_Voidfinger: 764, + Maffer_Dragonhand: 765, + Winged_Death: 766, + The_Tormentor: 767, + Taintbreeder: 768, + Riftwraith_the_Cannibal: 769, + Infector_of_Souls: 770, + Lord_De_Seis: 771, + Grand_Vizier_of_Chaos: 772, + The_Cow_King: 773, + Corpsefire: 774, + The_Feature_Creep: 775, + Siege_Boss: 776, + Ancient_Barbarian_1: 777, + Ancient_Barbarian_2: 778, + Ancient_Barbarian_3: 779, + Axe_Dweller: 780, + Bonesaw_Breaker: 781, + Dac_Farren: 782, + Megaflow_Rectifier: 783, + Eyeback_Unleashed: 784, + Threash_Socket: 785, + Pindleskin: 786, + Snapchip_Shatter: 787, + Anodized_Elite: 788, + Vinvear_Molech: 789, + Sharp_Tooth_Sayer: 790, + Magma_Torquer: 791, + Blaze_Ripper: 792, + Frozenstein: 793, + Nihlathak: 794, + Baal_Subject_1: 795, + Baal_Subject_2: 796, + Baal_Subject_3: 797, + Baal_Subject_4: 798, + Baal_Subject_5: 799 + }; + + var UIFlags = { + Inventory_open: 0x01, + Character_Stat_screen_open: 0x02, + quick_skill: 0x03, + skill: 0x04, + Chat_box_open_typing_something: 0x05, + unknown1: 0x06, + unknown2: 0x07, + npc_menu: 0x08, + Esc_menu: 0x09, + Automap_is_on: 0x0A, + config_controls: 0x0B, + Shop_open_at_NPC: 0x0C, + alt_show_items: 0x0D, + cash: 0x0E, + quest: 0x0F, + unknown3: 0x10, + questlog_button: 0x11, + status_area: 0x12, + unknown4: 0x13, + waypoint: 0x14, + mini_panel: 0x15, + party: 0x16, + Trade_Prompt_up_ok_cancel_player_or_in_Trade_w_player: 0x17, + msgs: 0x18, + Stash_is_open: 0x19, + Cube_is_open: 0x1A, + unknown5: 0x1B, + unknown6: 0x1C, + unknown7: 0x1D, + unknown8: 0x1E, + Belt_show_all_is_toggled: 0x1F, + unknown9: 0x20, + help: 0x21, + unknown10: 0x22, + unknown11: 0x23, + Merc_screen: 0x24, + scroll_of_whatever: 0x25 + }; + + var WaypointsHex = { + Act1: { + Rogue_Encampment: 0x01, + Cold_Plains: 0x03, + Stony_Field: 0x04, + Dark_Wood: 0x05, + Black_Marsh: 0x06, + Outer_Cloister: 0x1b, + Jail_level_1: 0x1d, + Inner_Cloister: 0x20, + Catacombs_level_2: 0x23 + }, + Act2: { + Lut_Gholein: 0x28, + Sewers_level_2: 0x30, + Dry_Hills: 0x2a, + Halls_of_the_Dead_level_2: 0x39, + Far_Oasis: 0x2b, + Lost_City: 0x2c, + Palace_Cellar_level_1: 0x34, + Arcane_Sanctuary: 0x4a, + Canyon_of_the_Magi: 0x2e + }, + Act3: { + Kurast_Docks: 0x4b, + Spider_Forest: 0x4c, + Great_Marsh: 0x4d, + Flayer_Jungle: 0x4e, + Lower_Kurast: 0x4f, + Kurast_Bazaar: 0x50, + Upper_Kurast: 0x51, + Travincal: 0x53, + Durance_of_Hate_level_2: 0x65 + }, + Act4: { + Pandemonium_Fortress: 0x67, + City_of_the_Damned: 0x6a, + River_of_Flames: 0x6b + }, + Act5: { + Harrogath: 0x6d, + Frigid_Highlands: 0x6f, + Arreat_Plateau: 0x70, + Crystalline_Passage: 0x71, + Halls_of_Pain: 0x73, + Glacial_Trail: 0x7b, + Frozen_Tundra: 0x75, + The_Ancients_Way: 0x76, + Worldstone_Keep_level_2: 0x81 + } + }; + + var Waypoints = { + Act1: { + ROGUE_ENCAMPMENT: 0, + COLD_PLAINS: 1, + STONY_FIELD: 2, + DARK_WOOD: 3, + BLACK_MARSH: 4, + OUTER_CLOISTER: 5, + JAIL_LEVEL_1: 6, + INNER_CLOISTER: 7, + CATACOMBS_LEVEL_2: 8 + }, + Act2: { + LUT_GHOLEIN: 9, + SEWERS_LEVEL_2: 10, + DRY_HILLS: 11, + HALLS_OF_THE_DEAD_LEVEL_2: 12, + FAR_OASIS: 13, + LOST_CITY: 14, + PALACE_CELLAR_LEVEL_1: 15, + ARCANE_SANCTUARY: 16, + CANYON_OF_THE_MAGI: 17 + }, + Act3: { + KURAST_DOCKTOWN: 18, + SPIDER_FOREST: 19, + GREAT_MARSH: 20, + FLAYER_JUNGLE: 21, + LOWER_KURAST: 22, + KURAST_BAZAAR: 23, + UPPER_KURAST: 24, + TRAVINCAL: 25, + DURANCE_OF_HATE_LEVEL_2: 26 + }, + Act4: { + THE_PANDEMONIUM_FORTRESS: 27, + CITY_OF_THE_DAMNED: 28, + RIVER_OF_FLAME: 29 + }, + Act5: { + HARROGATH: 30, + FRIGID_HIGHLANDS: 31, + ARREAT_PLATEAU: 32, + CRYSTALINE_PASSAGE: 33, + GLACIAL_TRAIL: 34, + HALLS_OF_PAIN: 35, + FROZEN_TUNDRA: 36, + THE_ANCIENTS_WAY: 37, + THE_WORLDSTONE_KEEP_LEVEL_2: 38 + } + }; + + var ColorCodes = { + White: "ÿc0", + Red: "ÿc1", + Neon_Green: "ÿc2", + Blue: "ÿc3", + Dark_Gold: "ÿc4", + Gray: "ÿc5", + Black: "ÿc6", + Light_Gold: "ÿc7", + Orange: "ÿc8", + Yellow: "ÿc9", + Dark_Green: "ÿc:", + Purple: "ÿc;", + Green: "ÿc<" + }; + + var ItemClassIds = { + Hand_Axe: 0, + Axe: 1, + Double_Axe: 2, + Military_Pick: 3, + War_Axe: 4, + Large_Axe: 5, + Broad_Axe: 6, + Battle_Axe: 7, + Great_Axe: 8, + Giant_Axe: 9, + Wand: 10, + Yew_Wand: 11, + Bone_Wand: 12, + Grim_Wand: 13, + Club: 14, + Scepter: 15, + Grand_Scepter: 16, + War_Scepter: 17, + Spiked_Club: 18, + Mace: 19, + Morning_Star: 20, + Flail: 21, + War_Hammer: 22, + Maul: 23, + Great_Maul: 24, + Short_Sword: 25, + Scimitar: 26, + Sabre: 27, + Falchion: 28, + Crystal_Sword: 29, + Broad_Sword: 30, + Long_Sword: 31, + War_Sword: 32, + Two_handed_Sword: 33, + Claymore: 34, + Giant_Sword: 35, + Bastard_Sword: 36, + Flamberge: 37, + Great_Sword: 38, + Dagger: 39, + Dirk: 40, + Kris: 41, + Blade: 42, + Throwing_Knife: 43, + Throwing_Axe: 44, + Balanced_Knife: 45, + Balanced_Axe: 46, + Javelin: 47, + Pilum: 48, + Short_Spear: 49, + Glaive: 50, + Throwing_Spear: 51, + Spear: 52, + Trident: 53, + Brandistock: 54, + Spetum: 55, + Pike: 56, + Bardiche: 57, + Voulge: 58, + Scythe: 59, + Poleaxe: 60, + Halberd: 61, + War_Scythe: 62, + Short_Staff: 63, + Long_Staff: 64, + Gnarled_Staff: 65, + Battle_Staff: 66, + War_Staff: 67, + Short_Bow: 68, + Hunters_Bow: 69, + Long_Bow: 70, + Composite_Bow: 71, + Short_Battle_Bow: 72, + Long_Battle_ow: 73, + Short_War_Bow: 74, + Long_War_Bow: 75, + Light_CrossBow: 76, + CrossBow: 77, + Heavy_CrossBow: 78, + Repeating_CrossBow: 79, + Rancid_Gas_Potion: 80, + Oil_Potion: 81, + Choking_Gas_Potion: 82, + Exploding_Potion: 83, + Strangling_Gas_Potion: 84, + Fulminating_Potion: 85, + Decoy_Gidbinn: 86, + The_Gidbinn: 87, + Wirts_Leg: 88, + Horadric_Malus: 89, + Hellforge_Hammer: 90, + Horadric_Staff: 91, + Staff_of_Kings: 92, + Hatchet: 93, + Cleaver: 94, + Twin_Axe: 95, + Crowbill: 96, + Naga: 97, + Military_Axe: 98, + Bearded_Axe: 99, + Tabar: 100, + Gothic_Axe: 101, + Ancient_Axe: 102, + Burnt_Wand: 103, + Petrified_Wand: 104, + Tomb_Wand: 105, + Grave_Wand: 106, + Cudgel: 107, + Rune_Scepter: 108, + Holy_Water_Sprinkler: 109, + Divine_Scepter: 110, + Barbed_Club: 111, + Flanged_Mace: 112, + Jagged_Star: 113, + Knout: 114, + Battle_Hammer: 115, + War_Club: 116, + Martel_De_Fer: 117, + Gladius: 118, + Cutlass: 119, + Shamshir: 120, + Tulwar: 121, + Dimensional_Blade: 122, + Battle_Sword: 123, + Rune_Sword: 124, + Ancient_Sword: 125, + Espandon: 126, + Dacian_Falx: 127, + Tusk_Sword: 128, + Gothic_Sword: 129, + Zweihander: 130, + Executioner_Sword: 131, + Poignard: 132, + Rondel: 133, + Cinquedeas: 134, + Stiletto: 135, + Battle_Dart: 136, + Francisca: 137, + War_Dart: 138, + Hurlbat: 139, + War_Javelin: 140, + Great_Pilum: 141, + Simbilan: 142, + Spiculum: 143, + Harpoon: 144, + War_Spear: 145, + Fuscina: 146, + War_Fork: 147, + Yari: 148, + Lance: 149, + Lochaber_Axe: 150, + Bill: 151, + Battle_Scythe: 152, + Partizan: 153, + Bec_De_Corbin: 154, + Grim_Scythe: 155, + Jo_Staff: 156, + Quarter_Staff: 157, + Cedar_Staff: 158, + Gothic_Staff: 159, + Rune_Staff: 160, + Edge_Bow: 161, + Razor_Bow: 162, + Cedar_Bow: 163, + Double_Bow: 164, + Short_Siege_Bow: 165, + Large_Siege_Bow: 166, + Rune_Bow: 167, + Gothic_Bow: 168, + Arbalest: 169, + Siege_Crossbow: 170, + Ballista: 171, + Chu_ko_nu: 172, + Khalims_Flail: 173, + Khalims_Will: 174, + Katar: 175, + Wrist_Blade: 176, + Hatchet_Hands: 177, + Cestus: 178, + Claws: 179, + Blade_Talons: 180, + Scissors_Katar: 181, + Quhab: 182, + Wrist_Spike: 183, + Fascia: 184, + Hand_Scythe: 185, + Greater_Claws: 186, + Greater_Talons: 187, + Scissors_Quhab: 188, + Suwayyah: 189, + Wrist_Sword: 190, + War_Fist: 191, + Battle_Cestus: 192, + Feral_Claws: 193, + Runic_Talons: 194, + Scissors_Suwayyah: 195, + Tomahawk: 196, + Small_Crescent: 197, + Ettin_Axe: 198, + War_Spike: 199, + Berserker_Axe: 200, + Feral_Axe: 201, + Silver_Edged_Axe: 202, + Decapitator: 203, + Champion_Axe: 204, + Glorious_Axe: 205, + Polished_Wand: 206, + Ghost_Wand: 207, + Lich_Wand: 208, + Unearthed_Wand: 209, + Truncheon: 210, + Mighty_Scepter: 211, + Seraph_Rod: 212, + Caduceus: 213, + Tyrant_Club: 214, + Reinforced_Mace: 215, + Devil_Star: 216, + Scourge: 217, + Legendary_Mallet: 218, + Ogre_Maul: 219, + Thunder_Maul: 220, + Falcata: 221, + Ataghan: 222, + Elegant_Blade: 223, + Hydra_Edge: 224, + Phase_Blade: 225, + Conquest_Sword: 226, + Cryptic_Sword: 227, + Mythical_Sword: 228, + Legend_Sword: 229, + Highland_Blade: 230, + Balrog_Blade: 231, + Champion_Sword: 232, + Colossus_Sword: 233, + Colossus_Blade: 234, + Bone_Knife: 235, + Mithril_Point: 236, + Fanged_Knife: 237, + Legend_Spike: 238, + Flying_Knife: 239, + Flying_Axe: 240, + Winged_Knife: 241, + Winged_Axe: 242, + Hyperion_Javelin: 243, + Stygian_Pilum: 244, + Balrog_Spear: 245, + Ghost_Glaive: 246, + Winged_Harpoon: 247, + Hyperion_Spear: 248, + Stygian_Pike: 249, + Mancatcher: 250, + Ghost_Spear: 251, + War_Pike: 252, + Ogre_Axe: 253, + Colossus_Voulge: 254, + Thresher: 255, + Cryptic_Axe: 256, + Great_Poleaxe: 257, + Giant_Thresher: 258, + Walking_Stick: 259, + Stalagmite: 260, + Elder_Staff: 261, + Shillelagh: 262, + Archon_Staff: 263, + Spider_Bow: 264, + Blade_Bow: 265, + Shadow_Bow: 266, + Great_Bow: 267, + Diamond_Bow: 268, + Crusader_Bow: 269, + Ward_Bow: 270, + Hydra_Bow: 271, + Pellet_Bow: 272, + Gorgon_CrossBow: 273, + Colossus_CrossBow: 274, + Demon_CrossBow: 275, + Eagle_Orb: 276, + Sacred_Globe: 277, + Smoked_Sphere: 278, + Clasped_Orb: 279, + Jareds_Stone: 280, + Stag_Bow: 281, + Reflex_Bow: 282, + Maiden_Spear: 283, + Maiden_Pike: 284, + Maiden_Javelin: 285, + Glowing_Orb: 286, + Crystalline_Globe: 287, + Cloudy_Sphere: 288, + Sparkling_Ball: 289, + Swirling_Crystal: 290, + Ashwood_Bow: 291, + Ceremonial_Bow: 292, + Ceremonial_Spear: 293, + Ceremonial_Pike: 294, + Ceremonial_Javelin: 295, + Heavenly_Stone: 296, + Eldritch_Orb: 297, + Demon_Heart: 298, + Vortex_Orb: 299, + Dimensional_Shard: 300, + Matriarchal_Bow: 301, + Grandmatron_Bow: 302, + Matriarchal_Spear: 303, + Matriarchal_Pike: 304, + Matriarchal_Javelin: 305, + Cap: 306, + Skull_Cap: 307, + Helm: 308, + Full_Helm: 309, + Great_Helm: 310, + Crown: 311, + Mask: 312, + Quilted_Armor: 313, + Leather_Armor: 314, + Hardleather_Armor: 315, + Studded_Leather: 316, + Ring_Mail: 317, + Scale_Mail: 318, + Chain_Mail: 319, + Breast_Plate: 320, + Splint_Mail: 321, + Plate_Mail: 322, + Field_Plate: 323, + Gothic_Plate: 324, + Full_Plate_Mail: 325, + Ancient_Armor: 326, + Light_Plate: 327, + Buckler: 328, + Small_Shield: 329, + Large_Shield: 330, + Kite_Shield: 331, + Tower_Shield: 332, + Gothic_Shield: 333, + Leather_Gloves: 334, + Heavy_Gloves: 335, + Chain_Gloves: 336, + Light_Gauntlets: 337, + Gauntlets: 338, + Boots: 339, + Heavy_Boots: 340, + Chain_Boots: 341, + Light_Plated_Boots: 342, + Greaves: 343, + Sash: 344, + Light_Belt: 345, + Belt: 346, + Heavy_Belt: 347, + Plated_Belt: 348, + Bone_Helm: 349, + Bone_Shield: 350, + Spiked_Shield: 351, + War_Hat: 352, + Sallet: 353, + Casque: 354, + Basinet: 355, + Winged_Helm: 356, + Grand_Crown: 357, + Death_Mask: 358, + Ghost_Armor: 359, + Serpentskin_Armor: 360, + Demonhide_Armor: 361, + Trellised_Armor: 362, + Linked_Mail: 363, + Tigulated_Mail: 364, + Mesh_Armor: 365, + Cuirass: 366, + Russet_Armor: 367, + Templar_Coat: 368, + Sharktooth_Armor: 369, + Embossed_Plate: 370, + Chaos_Armor: 371, + Ornate_Plate: 372, + Mage_Plate: 373, + Defender: 374, + Round_Shield: 375, + Scutum: 376, + Dragon_Shield: 377, + Pavise: 378, + Ancient_Shield: 379, + Demonhide_Gloves: 380, + Sharkskin_Gloves: 381, + Heavy_Bracers: 382, + Battle_Gauntlets: 383, + War_Gauntlets: 384, + Demonhide_Boots: 385, + Sharkskin_Boots: 386, + Mesh_Boots: 387, + Battle_Boots: 388, + War_Boots: 389, + Demonhide_Sash: 390, + Sharkskin_Belt: 391, + Mesh_Belt: 392, + Battle_Belt: 393, + War_Belt: 394, + Grim_Helm: 395, + Grim_Shield: 396, + Barbed_Shield: 397, + Wolf_Head: 398, + Hawk_Helm: 399, + Antlers: 400, + Falcon_Mask: 401, + Spirit_Mask: 402, + Jawbone_Cap: 403, + Fanged_Helm: 404, + Horned_Helm: 405, + Assault_Helmet: 406, + Avenger_Guard: 407, + Targe: 408, + Rondache: 409, + Heraldic_Shield: 410, + Aerin_Shield: 411, + Crown_Shield: 412, + Preserved_Head: 413, + Zombie_Head: 414, + Unraveller_Head: 415, + Gargoyle_Head: 416, + Demon_Head: 417, + Circlet: 418, + Coronet: 419, + Tiara: 420, + Diadem: 421, + Shako: 422, + Hydra_Skull: 423, + Armet: 424, + Giant_Conch: 425, + Spired_Helm: 426, + Corona: 427, + Demonhead: 428, + Dusk_Shroud: 429, + Wyrm_Hide: 430, + Scarab_Husk: 431, + Wire_Fleece: 432, + Diamond_Mail: 433, + Loricated_Mail: 434, + Bone_Weave: 435, + Great_Hauberk: 436, + Balrog_Skin: 437, + Hellforge_Plate: 438, + Kraken_Shell: 439, + Lacquered_Plate: 440, + Shadow_Plate: 441, + Sacred_Armor: 442, + Archon_Plate: 443, + Heater: 444, + Luna: 445, + Hyperion: 446, + Monarch: 447, + Aegis: 448, + Ward: 449, + Bramble_Mitts: 450, + Vampirebone_Gloves: 451, + Vambraces: 452, + Crusader_Gauntlets: 453, + Ogre_Gauntlets: 454, + Wyrmhide_Boots: 455, + Scarabshell_Boots: 456, + Boneweave_Boots: 457, + Mirrored_Boots: 458, + Myrmidon_Greaves: 459, + Spiderweb_Sash: 460, + Vampirefang_Belt: 461, + Mithril_Coil: 462, + Troll_Belt: 463, + Colossus_Girdle: 464, + Bone_Visage: 465, + Troll_Nest: 466, + Blade_Barrier: 467, + Alpha_Helm: 468, + Griffon_Headdress: 469, + Hunters_Guise: 470, + Sacred_Feathers: 471, + Totemic_Mask: 472, + Jawbone_Visor: 473, + Lion_Helm: 474, + Rage_Mask: 475, + Savage_Helmet: 476, + Slayer_Guard: 477, + Akaran_Targe: 478, + Akaran_Rondache: 479, + Protector_Shield: 480, + Gilded_Shield: 481, + Royal_Shield: 482, + Mummified_Trophy: 483, + Fetish_Trophy: 484, + Sexton_Trophy: 485, + Cantor_Trophy: 486, + Hierophant_Trophy: 487, + Blood_Spirit: 488, + Sun_Spirit: 489, + Earth_Spirit: 490, + Sky_Spirit: 491, + Dream_Spirit: 492, + Carnage_Helm: 493, + Fury_Visor: 494, + Destroyer_Helm: 495, + Conqueror_Crown: 496, + Guardian_Crown: 497, + Sacred_Targe: 498, + Sacred_Rondache: 499, + Kurast_Shield: 500, + Zakarum_Shield: 501, + Vortex_Shield: 502, + Minion_Skull: 503, + Hellspawn_Skull: 504, + Overseer_Skull: 505, + Succubus_Skull: 506, + Bloodlord_Skull: 507, + Elixir: 508, + Stamina_Potion: 513, + Antidote_Potion: 514, + Rejuvenation_Potion: 515, + Full_Rejuvenation_Potion: 516, + Thawing_Potion: 517, + Tome_Of_Town_Portal: 518, + Tome_Of_Identify: 519, + Amulet: 520, + Viper_Amulet: 521, + Ring: 522, + Gold: 523, + Scroll_Of_Inifuss: 524, + Key_To_The_Cairn_Stones: 525, + Arrows: 526, + Torch: 527, + Bolts: 528, + Scroll_Of_Town_Portal: 529, + Scroll_Of_Identify: 530, + Heart: 531, + Brain: 532, + Jawbone: 533, + Eye: 534, + Horn: 535, + Tail: 536, + Flag: 537, + Fang: 538, + Quill: 539, + Soul: 540, + Scalp: 541, + Spleen: 542, + Key: 543, + The_Black_Tower_Key: 544, + Potion_of_Life: 545, + A_Jade_Figurine: 546, + The_Golden_Bird: 547, + Lam_Esens_Tome: 548, + Horadric_Cube: 549, + Horadric_Scroll: 550, + Mephistos_Soulstone: 551, + Book_Of_Skill: 552, + Khalims_Eye: 553, + Khalims_Heart: 554, + Khalims_Brain: 555, + Ear: 556, + Chipped_Amethyst: 557, + Flawed_Amethyst: 558, + Amethyst: 559, + Flawless_Amethyst: 560, + Perfect_Amethyst: 561, + Chipped_Topaz: 562, + Flawed_Topaz: 563, + Topaz: 564, + Flawless_Topaz: 565, + Perfect_Topaz: 566, + Chipped_Sapphire: 567, + Flawed_Sapphire: 568, + Sapphire: 569, + Flawless_Sapphire: 570, + Perfect_Sapphire: 571, + Chipped_Emerald: 572, + Flawed_Emerald: 573, + Emerald: 574, + Flawless_Emerald: 575, + Perfect_Emerald: 576, + Chipped_Ruby: 577, + Flawed_Ruby: 578, + Ruby: 579, + Flawless_Ruby: 580, + Perfect_Ruby: 581, + Chipped_Diamond: 582, + Flawed_Diamond: 583, + Diamond: 584, + Flawless_Diamond: 585, + Perfect_Diamond: 586, + Minor_Healing_Potion: 587, + Light_Healing_Potion: 588, + Healing_Potion: 589, + Greater_Healing_Potion: 590, + Super_Healing_Potion: 591, + Minor_Mana_Potion: 592, + Light_Mana_Potion: 593, + Mana_Potion: 594, + Greater_Mana_Potion: 595, + Super_Mana_Potion: 596, + Chipped_Skull: 597, + Flawed_Skull: 598, + Skull: 599, + Flawless_Skull: 600, + Perfect_Skull: 601, + Herb: 602, + Small_Charm: 603, + Large_Charm: 604, + Grand_Charm: 605, + El_Rune: 610, + Eld_Rune: 611, + Tir_Rune: 612, + Nef_Rune: 613, + Eth_Rune: 614, + Ith_Rune: 615, + Tal_Rune: 616, + Ral_Rune: 617, + Ort_Rune: 618, + Thul_Rune: 619, + Amn_Rune: 620, + Sol_Rune: 621, + Shael_Rune: 622, + Dol_Rune: 623, + Hel_Rune: 624, + Io_Rune: 625, + Lum_Rune: 626, + Ko_Rune: 627, + Fal_Rune: 628, + Lem_Rune: 629, + Pul_Rune: 630, + Um_Rune: 631, + Mal_Rune: 632, + Ist_Rune: 633, + Gul_Rune: 634, + Vex_Rune: 635, + Ohm_Rune: 636, + Lo_Rune: 637, + Sur_Rune: 638, + Ber_Rune: 639, + Jah_Rune: 640, + Cham_Rune: 641, + Zod_Rune: 642, + Jewel: 643, + Malahs_Potion: 644, + Scroll_Of_Knowledge: 645, + Scroll_Of_Resistance: 646, + Key_Of_Terror: 647, + Key_Of_Hate: 648, + Key_Of_Destruction: 649, + Diablos_Horn: 650, + Baals_Eye: 651, + Mephistos_Brain: 652, + Token_of_Absolution: 653, + Twisted_Essence_Of_Suffering: 654, + Charged_Essence_Of_Hatred: 655, + Burning_Essence_Of_Terror: 656, + Festering_Essence_Of_Destruction: 657, + Standard_Of_Heroes: 658 + }; + + var SpecType = { + // 0xF is comes from 0x1 | 0x2 | 0x4 | 0x8 (bitwise OR operator, meaning minion or boss or unique or champion) + Normal: 0x1, + Champion: 0x2, + Boss: 0x4, + Minion: 0x8 + }; + + var ClassID = { + Amazon: 0, + Sorceress: 1, + Necromancer: 2, + Paladin: 3, + Barbarian: 4, + Druid: 5, + Assassin: 6 + }; + + //states.txt + var States = { + NONE: 0, + FREEZE: 1, + POISON: 2, + RESISTFIRE: 3, + RESISTCOLD: 4, + RESISTLIGHT: 5, + RESISTMAGIC: 6, + PLAYERBODY: 7, + RESISTALL: 8, + AMPLIFYDAMAGE: 9, + FROZENARMOR: 10, + COLD: 11, + INFERNO: 12, + BLAZE: 13, + BONEARMOR: 14, + CONCENTRATE: 15, + ENCHANT: 16, + INNERSIGHT: 17, + SKILL_MOVE: 18, + WEAKEN: 19, + CHILLINGARMOR: 20, + STUNNED: 21, + SPIDERLAY: 22, + DIMVISION: 23, + SLOWED: 24, + FETISHAURA: 25, + SHOUT: 26, + TAUNT: 27, + CONVICTION: 28, + CONVICTED: 29, + ENERGYSHIELD: 30, + VENOMCLAWS: 31, + BATTLEORDERS: 32, + MIGHT: 33, + PRAYER: 34, + HOLYFIRE: 35, + THORNS: 36, + DEFIANCE: 37, + THUNDERSTORM: 38, + LIGHTNINGBOLT: 39, + BLESSEDAIM: 40, + STAMINA: 41, + CONCENTRATION: 42, + HOLYWIND: 43, + HOLYWINDCOLD: 44, + CLEANSING: 45, + HOLYSHOCK: 46, + SANCTUARY: 47, + MEDITATION: 48, + FANATICISM: 49, + REDEMPTION: 50, + BATTLECOMMAND: 51, + PREVENTHEAL: 52, + CONVERSION: 53, + UNINTERRUPTABLE: 54, + IRONMAIDEN: 55, + TERROR: 56, + ATTRACT: 57, + LIFETAP: 58, + CONFUSE: 59, + DECREPIFY: 60, + LOWERRESIST: 61, + OPENWOUNDS: 62, + DOPPLEZON: 63, + CRITICALSTRIKE: 64, + DODGE: 65, + AVOID: 66, + PENETRATE: 67, + EVADE: 68, + PIERCE: 69, + WARMTH: 70, + FIREMASTERY: 71, + LIGHTNINGMASTERY: 72, + COLDMASTERY: 73, + SWORDMASTERY: 74, + AXEMASTERY: 75, + MACEMASTERY: 76, + POLEARMMASTERY: 77, + THROWINGMASTERY: 78, + SPEARMASTERY: 79, + INCREASEDSTAMINA: 80, + IRONSKIN: 81, + INCREASEDSPEED: 82, + NATURALRESISTANCE: 83, + FINGERMAGECURSE: 84, + NOMANAREGEN: 85, + JUSTHIT: 86, + SLOWMISSILES: 87, + SHIVERARMOR: 88, + BATTLECRY: 89, + BLUE: 90, + RED: 91, + DEATH_DELAY: 92, + VALKYRIE: 93, + FRENZY: 94, + BERSERK: 95, + REVIVE: 96, + ITEMFULLSET: 97, + SOURCEUNIT: 98, + REDEEMED: 99, + HEALTHPOT: 100, + HOLYSHIELD: 101, + JUST_PORTALED: 102, + MONFRENZY: 103, + CORPSE_NODRAW: 104, + ALIGNMENT: 105, + MANAPOT: 106, + SHATTER: 107, + SYNC_WARPED: 108, + CONVERSION_SAVE: 109, + PREGNANT: 110, + 111: 111, + RABIES: 112, + DEFENSE_CURSE: 113, + BLOOD_MANA: 114, + BURNING: 115, + DRAGONFLIGHT: 116, + MAUL: 117, + CORPSE_NOSELECT: 118, + SHADOWWARRIOR: 119, + FERALRAGE: 120, + SKILLDELAY: 121, + PROGRESSIVE_DAMAGE: 122, + PROGRESSIVE_STEAL: 123, + PROGRESSIVE_OTHER: 124, + PROGRESSIVE_FIRE: 125, + PROGRESSIVE_COLD: 126, + PROGRESSIVE_LIGHTNING: 127, + SHRINE_ARMOR: 128, + SHRINE_COMBAT: 129, + SHRINE_RESIST_LIGHTNING: 130, + SHRINE_RESIST_FIRE: 131, + SHRINE_RESIST_COLD: 132, + SHRINE_RESIST_POISON: 133, + SHRINE_SKILL: 134, + SHRINE_MANA_REGEN: 135, + SHRINE_STAMINA: 136, + SHRINE_EXPERIENCE: 137, + FENRIS_RAGE: 138, + WOLF: 139, + BEAR: 140, + BLOODLUST: 141, + CHANGECLASS: 142, + ATTACHED: 143, + HURRICANE: 144, + ARMAGEDDON: 145, + INVIS: 146, + BARBS: 147, + WOLVERINE: 148, + OAKSAGE: 149, + VINE_BEAST: 150, + CYCLONEARMOR: 151, + CLAWMASTERY: 152, + CLOAK_OF_SHADOWS: 153, + RECYCLED: 154, + WEAPONBLOCK: 155, + CLOAKED: 156, + QUICKNESS: 157, + BLADESHIELD: 158, + FADE: 159 + }; + + +var ClickType = { + "Left_Click": 0, + "Right_Click": 1, + "Shift_Left_Click": 2, + "Left_Click_Merc_Location": 4 + }; + +var ClickTypeParty = { + "Allow_loot_corpse": 0, + "Hostile_Player": 1, + "Join_party": 2, + "Leave_party": 3 // (doesn't matter which party is passed in) +}; + + // http://docs.d2bs.org/classUnit.html#a60b8bec5206902278dfbbebe75c3617e + var ItemLocation = { + Ground: 0, + Equipped: 1, + Belt: 2, + Inventory: 3, + Store: 4, + Trade: 5, + Cube: 6, + Stash: 7 + }; + + // http://docs.d2bs.org/classMe.html#ace5f9a9c6a8139fbe30ca258e2f1bdc5 + var ItemQuality = { + Low_Quality: 1, + Normal: 2, + Superior: 3, + Magic: 4, + Set: 5, + Rare: 6, + Unique: 7, + Crafted: 8 + }; + + var ItemBodyLocation = { + NONE: 0, + HEAD: 1, + NECK: 2, + TORSO: 3, + RIGHT_ARM: 4, + LEFT_ARM: 5, + RIGHT_RING: 6, + LEFT_RING: 7, + BELT: 8, + FEET: 9, + GLOVES: 10, + RIGHT_ARM_SECONDARY: 11, + LEFT_ARM_SECONDARY: 12 + }; + + // Item Flags, pass the 0x hex code to the getFlag(), eg; flag = getFlag(0x400000); + //**thanks to bluemind for testing and creating this wonderful list! + var ItemFlags = { + isRuneword: 0x4000000, //set if it is a runeword (note that 'ith' qualifies ;) + isNamed: 0x1000000, //has a custom name "Player's item" + unknown: 0x800000, //was set for all items tested (tested in inv, stash, store) + isEthereal: 0x400000, //0 if not ethereal + isRuneOrPot: 0x200000, //rune or potion, also set for mephisto's soulstone + isStartItem: 0x20000, //an item that a new character starts with (like javelin and buckler, and the minor healings at the start) + isEar: 0x10000, //a player ear + isNotInSocke: 0x4000, //0 if in socket, 0 if in belt, 0 if equipped or equipped by merc, 0 for gems/charms/.. + isInStore: 0x2000, //in trade or gamble screen + isSocketed: 0x800, //the item has sockets (they can be full or empty) + isRejuv: 0x400, //only seen set for full rejuvs for now + isBroken: 0x100, //just a bet, but i'm pretty sure it's correct + isSwitchOut: 0x80, //a weapon switch command was performed, and this item is no longer being used + isSwitchIn: 0x40, //a weapon switch command was performed, and this item is now being used + isIdentified: 0x10, //0 if unid + isInSocket: 0x8, //8 if in socket, valid for rune and jewels, not gems + isEquipped: 0x1 //player or merc is wearing the item (don't trust too much, especially when bit 9 is set) + }; + + var NTItemTypes = { + "shield": 2, + "armor": 3, + "gold": 4, + "bowquiver": 5, + "crossbowquiver": 6, + "playerbodypart": 7, + "herb": 8, + "potion": 9, + "ring": 10, + "elixir": 11, + "amulet": 12, + "charm": 13, + "notused1": 14, + "boots": 15, + "gloves": 16, + "notused2": 17, + "book": 18, + "belt": 19, + "gem": 20, + "torch": 21, + "scroll": 22, + "notused3": 23, + "scepter": 24, + "wand": 25, + "staff": 26, + "bow": 27, + "axe": 28, + "club": 29, + "sword": 30, + "hammer": 31, + "knife": 32, + "spear": 33, + "polearm": 34, + "crossbow": 35, + "mace": 36, + "helm": 37, + "missilepotion": 38, + "quest": 39, + "bodypart": 40, + "key": 41, + "throwingknife": 42, + "throwingaxe": 43, + "javelin": 44, + "weapon": 45, + "meleeweapon": 46, + "missileweapon": 47, + "thrownweapon": 48, + "comboweapon": 49, + "anyarmor": 50, + "anyshield": 51, + "miscellaneous": 52, + "socketfiller": 53, + "secondhand": 54, + "stavesandrods": 55, + "missile": 56, + "blunt": 57, + "jewel": 58, + "classspecific": 59, + "amazonitem": 60, + "barbarianitem": 61, + "necromanceritem": 62, + "paladinitem": 63, + "sorceressitem": 64, + "assassinitem": 65, + "druiditem": 66, + "handtohand": 67, + "orb": 68, + "voodooheads": 69, + "auricshields": 70, + "primalhelm": 71, + "pelt": 72, + "cloak": 73, + "rune": 74, + "circlet": 75, + "healingpotion": 76, + "manapotion": 77, + "rejuvpotion": 78, + "staminapotion": 79, + "antidotepotion": 80, + "thawingpotion": 81, + "smallcharm": 82, + "mediumcharm": 83, + "largecharm": 84, + "amazonbow": 85, + "amazonspear": 86, + "amazonjavelin": 87, + "assassinclaw": 88, + "magicbowquiv": 89, + "magicxbowquiv": 90, + "chippedgem": 91, + "flawedgem": 92, + "standardgem": 93, + "flawlessgem": 94, + "perfectgem": 95, + "amethyst": 96, + "diamond": 97, + "emerald": 98, + "ruby": 99, + "sapphire": 100, + "topaz": 101, + "skull": 102 + }; + + //http://docs.d2bs.org/classUnit.html#a45243122ae655f50179f96bc831bfb1d + var UnitType = { + Player: 0, + NPC: 1, + Object: 2, + Missile: 3, + Item: 4, + Warp: 5, + Cursor_Item: 100, + Selected_Unit: 101 + }; + + var BaseStat = { + items: 0, + monster_or_npc_stats: 1, + skilldesc: 2, + skills: 3, + objects: 4, + missiles: 5, + monstats2: 6, + itemstatcost: 7, + levels: 8, + leveldefs: 9, + lvlmaze: 10, + lvlsub: 11, + lvlwarp: 12, + lvlprest: 13, + lvltypes: 14, + charstats: 15, + setitems: 16, + uniqueitems: 17, + sets: 18, + itemtypes: 19, + runes: 20, + cubemain: 21, + gems: 22, + experience: 23, + pettype: 24, + SuperUniques: 25 + }; + + var UniqueObjectIds = { + "Test_Data": 0, + "Casket_5": 1, + "Shrine": 2, + "Casket_6": 3, + "Urn_1": 4, + "Large_Chest_R": 5, + "Large_Chest_L": 6, + "Barrel": 7, + "Tower_Tome": 8, + "Urn_2": 9, + "Bench": 10, + "Barrel_Exploding": 11, + "Rogue_Fountain": 12, + "Door_Gate_L": 13, + "Door_Gate_R": 14, + "Door_Wooden_L": 15, + "Door_Wooden_R": 16, + "StoneAlpha": 17, + "StoneBeta": 18, + "StoneGamma": 19, + "StoneDelta": 20, + "StoneLambda": 21, + "StoneTheta": 22, + "DoorCourtyard_L": 23, + "DoorCourtyard_R": 24, + "DoorCathedralDouble": 25, + "Cain_Captured": 26, + "DoorMonestaryDouble_R": 27, + "Hole_In_Ground": 28, + "Brazier": 29, + "Inifuss_Tree": 30, + "Fountain": 31, + "Crucifix": 32, + "Candles1": 33, + "Candles2": 34, + "Standard1": 35, + "Standard2": 36, + "Torch1_Tiki": 37, + "Torch2_Wall": 38, + "RogueBonfire": 39, + "River1": 40, + "River2": 41, + "River3": 42, + "River4": 43, + "River5": 44, + "Ambient_Sound": 45, + "Crate": 46, + "Andariels_Door": 47, + "RogueTorch": 48, + "RogueTorch2": 49, + "CasketR": 50, + "CasketL": 51, + "Urn_3": 52, + "Casket": 53, + "Rogue_Corpse_1": 54, + "Rogue_Corpse_2": 55, + "Rolling_Rogue_Corpse": 56, + "Rogue_On_A_Stick_1": 57, + "Rogue_On_A_Stick_2": 58, + "Town_Portal": 59, + "Permanent_Town_Portal": 60, + "Invis_Object": 61, + "Door_Cathedral_L": 62, + "Door_Cathedral_R": 63, + "Door_Wooden_L_2": 64, + "Invis_River_Sound1": 65, + "Invis_River_Sound2": 66, + "Ripple": 67, + "Ripple2": 68, + "Ripple3": 69, + "Ripple4": 70, + "Forest_Night_Sound_1": 71, + "Forest_Night_Sound_2": 72, + "Yeti_Dung": 73, + "Trap_Door": 74, + "Door_By_Dock": 75, + "Sewer_Drip": 76, + "Healthorama": 77, + "Invis_Town_Sound": 78, + "Casket_3": 79, + "Obelisk": 80, + "Forest_Altar": 81, + "Pool_Of_Blood": 82, + "Shrine1_1": 83, + "HealingWell": 84, + "HealthShrine": 85, + "Shrine2": 86, + "Tombchest_1_Large_L": 87, + "Tombchest_2_Large_R": 88, + "Mummy_CoffinL_Tomb": 89, + "Desert_Obelisk": 90, + "Tomb_Door_L": 91, + "Tomb_Door_R": 92, + "ManaShrine": 93, + "Urn_4": 94, + "Urn_5": 95, + "HealthShrine2": 96, + "MagicShrine": 97, + "Tomb_Door_L_2": 98, + "Tomb_Door_R_2": 99, + "Portal_To_Duriel": 100, + "Brazier3": 101, + "Floor_Brazier": 102, + "Flies": 103, + "Armor_Stand_1R": 104, + "Armor_Stand_2L": 105, + "Weapon_Rack_1R": 106, + "Weapon_Rack_2L": 107, + "Malus": 108, + "Shrine_HealthR": 109, + "Drinker": 110, + "Fountain_1": 111, + "Gesturer": 112, + "Fountain_2_Well": 113, + "Turner": 114, + "Fountain_3": 115, + "Snakewoman_Shrine": 116, + "Jungle_Torch": 117, + "Fountain_4": 118, + "Waypoint_Portal": 119, + "Healthshrine_Dungeun": 120, + "Placeholder_1": 121, + "Placeholder_2": 122, + "Innershrinehell2": 123, + "Innershrinehell3": 124, + "Ihobject3_Inner_Hell": 125, + "Skullpile_Inner_Hell": 126, + "Ihobject5_Inner_Hell": 127, + "Hobject4_Inner_Hell": 128, + "Secret_Door_1": 129, + "Pool_Wilderness": 130, + "Vile_Dog_Afterglow": 131, + "Cathedralwell_Inside": 132, + "Shrine3": 133, + "Shrine4": 134, + "Shrine5": 135, + "Shrine6": 136, + "Desertwell_Well_Desert_Tomb": 137, + "Cavewell_Caves": 138, + "Chest_Large_R": 139, + "Chest_Tall_R": 140, + "Chest_Med_R": 141, + "Jug1_Desert": 142, + "Jug2_Desert": 143, + "Chest1_L": 144, + "Waypointi_Inner_Hell": 145, + "Chest2_R_Chest_Med_L": 146, + "Chest_R_Chest_Large_R": 147, + "Chest_L_Tomb_Chest_L_Large": 148, + "Sun_Altar_Quest": 149, + "Shrine1": 150, + "Shrine4_1": 151, + "Holder_For_Horadric_Staff": 152, + "Tyraels_Door": 153, + "Guard_Corpse": 154, + "Rock_Wilderness": 155, + "Waypoint": 156, + "WildernessWaypoint": 157, + "Corpse": 158, + "Rockb_Wilderness": 159, + "Fire_Small": 160, + "Fire_Medium": 161, + "Fire_Large": 162, + "Cliff_Wilderness": 163, + "Mana_Well1": 164, + "Mana_Well2": 165, + "Mana_Well3_Tomb": 166, + "Mana_Well4_Harom": 167, + "Mana_Well5": 168, + "Log": 169, + "Jungle_Healwell": 170, + "Corpseb": 171, + "Health_Well_shrine_Desert": 172, + "Mana_Well_shrine_Desert": 173, + "Rockc_Wilderness": 174, + "Rockd_Wilderness": 175, + "Chest_L_med": 176, + "Chest_L_large": 177, + "Guard_On_A_Stick": 178, + "Bookshelf1": 179, + "Bookshelf2": 180, + "Jungle_Chest": 181, + "Tombcoffin": 182, + "Chest_L_med_Jungle": 183, + "Jungle_Shrine2": 184, + "Jungle_Object_Act3_1": 185, + "Jungle_Object_Act3_2": 186, + "Jungle_Object_Act3_3": 187, + "Jungle_Object_Act3_4": 188, + "Cain_Portal": 189, + "Jungle_Shrine3": 190, + "Jungle_Shrine4": 191, + "Tele_Pad": 192, + "Lam_Esens_Tome": 193, + "Stairsl": 194, + "Stairsr": 195, + "Test_Data_Floortrap": 196, + "Jungleshrine": 197, + "Chest_General_L": 198, + "Mafistoshrine": 199, + "Mafistoshrine2": 200, + "Mafistoshrine3": 201, + "Mafistomana": 202, + "Mafistolair": 203, + "Box": 204, + "Altar": 205, + "Mafistohealth": 206, + "Water_Rocks_In_Wrok": 207, + "Basket_1": 208, + "Basket_2": 209, + "Water_Logs_In_Ne_Logw": 210, + "Water_Rocks_Girl_In_Wrob": 211, + "Bubbles_In_Act3_Water": 212, + "Water_Logs_In_Logx": 213, + "Water_Rocks_In_Rokb": 214, + "Water_Rocks_Girl_In_Watc": 215, + "Water_Rocks_In_Waty": 216, + "Water_Logs_In_Logz": 217, + "Web_Covered_Tree_1": 218, + "Web_Covered_Tree_2": 219, + "Web_Covered_Tree_3": 220, + "Web_Covered_Tree_4": 221, + "Hobject1": 222, + "Cacoon": 223, + "Cacoon_2": 224, + "Hobject1_2": 225, + "Outershrinehell": 226, + "Water_Rock_Girl_Nw_Blgb": 227, + "Big_Log_Sw_Blga": 228, + "Slimedoor1": 229, + "Slimedoor2": 230, + "Outershrinehell2": 231, + "Outershrinehell3": 232, + "Hobject2": 233, + "Big_Log_Se_Blgc": 234, + "Big_Log_Nw_Blgd": 235, + "Health_Wellforhell": 236, + "Act3Waypoint_Town": 237, + "Waypointh": 238, + "Burning_Town": 239, + "Chest1_L_2": 240, + "Chest2_R_2": 241, + "Chest3_R_2": 242, + "Chest3_L_2": 243, + "Sewers": 244, + "Burning_Town2": 245, + "Sewers2": 246, + "Bed": 247, + "Bed2": 248, + "HellManaWell": 249, + "Exploding_Cow_or_Rare": 250, + "Gidbinn_Altar": 251, + "Gidbinn_Decoy": 252, + "Diablo_R_Light": 253, + "Diablo_L_Light": 254, + "Diablo_Start_Point": 255, + "Stool_For_Cabin": 256, + "Wood_For_Cabin": 257, + "More_Wood_For_Cabin": 258, + "Skeleton_Spawn_Hell_nw": 259, + "Holyshrine": 260, + "Spikes_For_Tombs_Floortrap": 261, + "Cathedral": 262, + "Jail1": 263, + "Jail2": 264, + "Jail3": 265, + "Goo_Pile": 266, + "Bank": 267, + "Wirts_Body": 268, + "Gold_Placeholder": 269, + "Guard_Corpse_2": 270, + "Dead_Villager_1": 271, + "Dead_Villager_2": 272, + "Flame_No_Damage": 273, + "Tiny_Pixel_Shaped_Thingie": 274, + "Health_Shrine": 275, + "Mana_Shrine": 276, + "Magic_Shrine": 277, + "Mana_Shrine2": 278, + "Magic_Shrine2": 279, + "Healthwell": 280, + "Manawell": 281, + "Shrine7": 282, + "Brazier_Celler": 283, + "Anubis_Coffin": 284, + "Brazier_General_Sewers": 285, + "Brazier_Tall": 286, + "Brazier_Small": 287, + "Waypoint_Celler": 288, + "Bed3": 289, + "IronGrateDoor_L": 290, + "IronGrateDoor_R": 291, + "Wooden_Grate_Door_L": 292, + "Wooden_Grate_Door_R": 293, + "Wooden_Door_L": 294, + "Wooden_Door_R": 295, + "Wall_Torch_L": 296, + "Wall_Torch_R": 297, + "Arcane_Portal": 298, + "MagicShrine3": 299, + "MagicShrine4": 300, + "HealthWell3": 301, + "ManaWell3": 302, + "MagicShrine6": 303, + "Telepad": 304, + "Telepad2": 305, + "Telepad3": 306, + "Arcane_Thing": 307, + "Arcane_Thing2": 308, + "Arcane_Thing3": 309, + "Arcane_Thing4": 310, + "Arcane_Thing5": 311, + "Arcane_Thing6": 312, + "Arcane_Thing7": 313, + "Harem_Guard_1": 314, + "Harem_Guard_2": 315, + "Harem_Guard_3": 316, + "Harem_Guard_4": 317, + "Harem_Blocker": 318, + "HealthWell4": 319, + "HealthWell5": 320, + "Test_Data2": 321, + "TombWell": 322, + "SewerWaypoint": 323, + "TravincalWaypoint": 324, + "MagicShrine7": 325, + "DeadBody": 326, + "Torch_sewer": 327, + "Torch_kurast": 328, + "Maf_Chest_Large_L": 329, + "Maf_Chest_Large_R": 330, + "Maf_Chest_Mid_L": 331, + "Maf_Chest_Mid_R": 332, + "Lair_Chest_Large_L": 333, + "Lair_Chestt_L": 334, + "Lair_Chest_Mid_R": 335, + "Lair_Chest_R": 336, + "Steeg_Stone": 337, + "Guild_Vault": 338, + "Trophy_Case": 339, + "Message_Board": 340, + "Mephisto_Bridge": 341, + "Hellgate": 342, + "ManaWell5": 343, + "HealthWell6": 344, + "Hellfire1": 345, + "Hellfire2": 346, + "Hellfire3": 347, + "Helllava1": 348, + "Helllava2": 349, + "Helllava3": 350, + "Lightsource1": 351, + "Lightsource1_2": 352, + "Lightsource1_3": 353, + "Horadric_Cube_Chest": 354, + "Horadric_Scroll_Chest": 355, + "Staff_Of_Kings_Chest": 356, + "Horazons_Journal": 357, + "Hell_Brazier": 358, + "Hell_Brazier2": 359, + "Rockpile": 360, + "MagicShrine8": 361, + "Basket": 362, + "HugeSkeleton": 363, + "Guy_For_Dungeon": 364, + "Casket2": 365, + "Sewer_Quest_Stairs": 366, + "Sewer_Quest_Lever": 367, + "Start_Position": 368, + "Trapped_Soul": 369, + "Torch": 370, + "LargeChestR": 371, + "Bonepile": 372, + "Skeleton_Spawn, _Ne": 373, + "Fog_Water_Rfga": 374, + "Not_Used": 375, + "Forge_Hell": 376, + "Portal_To_Guild": 377, + "Hratli_Start": 378, + "Hratli_End": 379, + "Burning_Guy": 380, + "Burning_Guy2": 381, + "Natalya_Start": 382, + "Guy_Stuck_In_Hell": 383, + "Guy_Stuck_In_Hell2": 384, + "Cain_Start_Position": 385, + "Stairsr2": 386, + "ArcanebigchestL": 387, + "ArcaneCasket": 388, + "ChestBig_R": 389, + "ChestSmall_L": 390, + "ChestSmall_R": 391, + "Diablo_Seal1": 392, + "Diablo_Seal2": 393, + "Diablo_Seal3": 394, + "Diablo_Seal4": 395, + "Diablo_Seal5": 396, + "Sparklychest": 397, + "PandamoniaWaypoint": 398, + "Fissure_For_Inner_Hell": 399, + "Brazier_For_Hell": 400, + "Smoke": 401, + "VallyWaypoint": 402, + "Hell_Brazier4": 403, + "Compelling_Orb": 404, + "Khalim_Chest": 405, + "Khalim_Chest2": 406, + "Khalim_Chest3": 407, + "Siege_Control": 408, + "PotOTorch_level_1": 409, + "FirePit_level_1": 410, + "Chest_R": 413, + "Shrine9": 414, + "Shrine10": 415, + "HiddenStash": 416, + "WildernessFlag": 417, + "Barrel_1": 418, + "Barrel2_1": 419, + "Wooden_Chest_L": 420, + "Shrine_3": 421, + "Mana_Shrine11": 422, + "Health_Shrine11": 423, + "BurialChest_L": 424, + "BurialChest_R": 425, + "Well": 426, + "Shrine2_9": 427, + "Shrine2_10": 428, + "Waypoint2": 429, + "Chest_L": 430, + "Woodchest_R": 431, + "Chest_SL": 432, + "Chest_SR": 433, + "Torch_1": 434, + "Camp_Fire": 435, + "Town_Torch": 436, + "Torch_2": 437, + "Burning_Bodies": 438, + "Burning_Pit": 439, + "Tribal_Flag": 440, + "Town_Flag": 441, + "Chandeleir": 442, + "Jar_1": 443, + "Jar_2": 444, + "Jar_3": 445, + "SwingingHeads": 446, + "Pole": 447, + "Skill_W_Rockpile": 448, + "Town_Main_Gate": 449, + "Skull_And_Rocks": 450, + "Hellgate2": 451, + "Banner_1": 452, + "Banner_2": 453, + "Exploding_Chest": 454, + "Special_Chest": 455, + "DeathPole_R": 456, + "DeathPole_L": 457, + "Temple_Altar": 458, + "Drehya_In_Town": 459, + "Drehya_Outside_Town": 460, + "Nihlathak_In_Town": 461, + "Nihlathak_Outside_Town": 462, + "Hidden_Stash": 463, + "Health_Shrine12": 464, + "Mana_Shrine12": 465, + "Evil_Urn": 466, + "IcecaveJar1": 467, + "IcecaveJar2": 468, + "IcecaveJar3": 469, + "IcecaveJar4": 470, + "IcecaveJar5": 471, + "IcecaveShrine2": 472, + "Caged_Fellow": 473, + "Statue_3": 474, + "Statue_1": 475, + "Statue_2": 476, + "Dead_Barbarian": 477, + "Client_Smoke": 478, + "IcecaveShrine2_1": 479, + "IcecaveTorch1": 480, + "IcecaveTorch2": 481, + "Expansion_Tiki_Torch": 482, + "ManaShrine13": 483, + "BaalHealthShrine": 484, + "Baals_Lair": 485, + "Baals_Lair2": 486, + "Baals_Lair3": 487, + "BaalMagicShrine": 488, + "Torch1": 489, + "Torch2": 490, + "ManaShrine14": 491, + "HealthShrine14": 492, + "Well2": 493, + "BaalWaypoint": 494, + "Shrine3_2": 495, + "WildernessWaypoint2": 496, + "Shrine3_3": 497, + "BaalWell": 498, + "BaalMagicShrine2": 499, + "Object1": 500, + "Woodchest_L_2": 501, + "Woodchest_R_2": 502, + "BaalMagicShrine3": 503, + "WoodChest_L": 504, + "WoodChest_2": 505, + "SwingingHeads2": 506, + "Debris": 507, + "Pen_Door": 508, + "TempleMagicShrine": 509, + "Pole2": 510, + "IcecaveWaypoint": 511, + "TempleMagicShrine2": 512, + "TempleWell": 513, + "Torch1_2": 514, + "Torch2_2": 515, + "Object1_2": 516, + "Object2": 517, + "BaalMrBox": 518, + "IcecaveWell": 519, + "TempleMagicShrine3": 520, + "TempleHealthShrine": 521, + "TempleManaShrine": 522, + "Blacksmith": 523, + "Baals_Lair_Tomb1": 524, + "Baals_Lair_Tomb2": 525, + "Baals_Lair_Tomb3": 526, + "Ice_Cave_BubblesU_01": 527, + "Ice_Cave_BubblesS_01": 528, + "Redbaals_Lair_Tomb1": 529, + "Redbaals_Lair_Tomb1L": 530, + "Redbaals_Lair_Tomb2": 531, + "Redbaals_Lair_Tomb2L": 532, + "Redbaals_Lair_Tomb3": 533, + "Redbaals_Lair_Tomb3L": 534, + "RedbaalsMrBox": 535, + "Redbaals_Torch1": 536, + "Redbaals_Torch2": 537, + "TempleCandles": 538, + "TempleWaypoint": 539, + "DeadPerson": 540, + "GroundTomb": 541, + "Larzuk_Greeting": 542, + "Larzuk_Standard": 543, + "GroundTombL": 544, + "DeadPerson2": 545, + "AncientsAltar": 546, + "Worldstone_Level1": 547, + "WeaponrackR": 548, + "WeaponrackL": 549, + "ArmourrackR": 550, + "ArmourrackL": 551, + "SummitTorch2": 552, + "FuneralPire": 553, + "BurningLogs": 554, + "Ice_Cave_Steam": 555, + "DeadPerson3": 556, + "Baals_Lair4": 557, + "Frozen_Anya": 558, + "BBQ_Bunny": 559, + "Baal_Torch_Big": 560, + "Invisible_Ancient": 561, + "Invisible_Base": 562, + "Worldstone_Chamber": 563, + "GlacialCaves_Level1": 564, + "Last_Cinematic": 565, + "Harrogath_LastPortal": 566, + "Zoo": 567, + "Keeper": 568, + "ThroneOfDest_Portal": 569, + "FireplaceGuy": 570, + "DoorBlocker": 571, + "DoorBlocker2": 572 + }; + + var UnitClassID = { + "skeleton1": 0, + "skeleton2": 1, + "skeleton3": 2, + "skeleton4": 3, + "skeleton5": 4, + "zombie1": 5, + "zombie2": 6, + "zombie3": 7, + "zombie4": 8, + "zombie5": 9, + "bighead1": 10, + "bighead2": 11, + "bighead3": 12, + "bighead4": 13, + "bighead5": 14, + "foulcrow1": 15, + "foulcrow2": 16, + "foulcrow3": 17, + "foulcrow4": 18, + "fallen1": 19, + "fallen2": 20, + "fallen3": 21, + "fallen4": 22, + "fallen5": 23, + "brute2": 24, + "brute3": 25, + "brute4": 26, + "brute5": 27, + "brute1": 28, + "sandraider1": 29, + "sandraider2": 30, + "sandraider3": 31, + "sandraider4": 32, + "sandraider5": 33, + "gorgon1": 34, + "gorgon2": 35, + "gorgon3": 36, + "gorgon4": 37, + "wraith1": 38, + "wraith2": 39, + "wraith3": 40, + "wraith4": 41, + "wraith5": 42, + "corruptrogue1": 43, + "corruptrogue2": 44, + "corruptrogue3": 45, + "corruptrogue4": 46, + "corruptrogue5": 47, + "baboon1": 48, + "baboon2": 49, + "baboon3": 50, + "baboon4": 51, + "baboon5": 52, + "goatman1": 53, + "goatman2": 54, + "goatman3": 55, + "goatman4": 56, + "goatman5": 57, + "fallenshaman1": 58, + "fallenshaman2": 59, + "fallenshaman3": 60, + "fallenshaman4": 61, + "fallenshaman5": 62, + "quillrat1": 63, + "quillrat2": 64, + "quillrat3": 65, + "quillrat4": 66, + "quillrat5": 67, + "sandmaggot1": 68, + "sandmaggot2": 69, + "sandmaggot3": 70, + "sandmaggot4": 71, + "sandmaggot5": 72, + "clawviper1": 73, + "clawviper2": 74, + "clawviper3": 75, + "clawviper4": 76, + "clawviper5": 77, + "sandleaper1": 78, + "sandleaper2": 79, + "sandleaper3": 80, + "sandleaper4": 81, + "sandleaper5": 82, + "pantherwoman1": 83, + "pantherwoman2": 84, + "pantherwoman3": 85, + "pantherwoman4": 86, + "swarm1": 87, + "swarm2": 88, + "swarm3": 89, + "swarm4": 90, + "scarab1": 91, + "scarab2": 92, + "scarab3": 93, + "scarab4": 94, + "scarab5": 95, + "mummy1": 96, + "mummy2": 97, + "mummy3": 98, + "mummy4": 99, + "mummy5": 100, + "unraveler1": 101, + "unraveler2": 102, + "unraveler3": 103, + "unraveler4": 104, + "unraveler5": 105, + "chaoshorde1": 106, + "chaoshorde2": 107, + "chaoshorde3": 108, + "chaoshorde4": 109, + "vulture1": 110, + "vulture2": 111, + "vulture3": 112, + "vulture4": 113, + "mosquito1": 114, + "mosquito2": 115, + "mosquito3": 116, + "mosquito4": 117, + "willowisp1": 118, + "willowisp2": 119, + "willowisp3": 120, + "willowisp4": 121, + "arach1": 122, + "arach2": 123, + "arach3": 124, + "arach4": 125, + "arach5": 126, + "thornhulk1": 127, + "thornhulk2": 128, + "thornhulk3": 129, + "thornhulk4": 130, + "vampire1": 131, + "vampire2": 132, + "vampire3": 133, + "vampire4": 134, + "vampire5": 135, + "batdemon1": 136, + "batdemon2": 137, + "batdemon3": 138, + "batdemon4": 139, + "batdemon5": 140, + "fetish1": 141, + "fetish2": 142, + "fetish3": 143, + "fetish4": 144, + "fetish5": 145, + "cain1": 146, + "gheed": 147, + "akara": 148, + "chicken": 149, + "kashya": 150, + "rat": 151, + "rogue1": 152, + "hellmeteor": 153, + "charsi": 154, + "warriv1": 155, + "andariel": 156, + "bird1": 157, + "bird2": 158, + "bat": 159, + "cr_archer1": 160, + "cr_archer2": 161, + "cr_archer3": 162, + "cr_archer4": 163, + "cr_archer5": 164, + "cr_lancer1": 165, + "cr_lancer2": 166, + "cr_lancer3": 167, + "cr_lancer4": 168, + "cr_lancer5": 169, + "sk_archer1": 170, + "sk_archer2": 171, + "sk_archer3": 172, + "sk_archer4": 173, + "sk_archer5": 174, + "warriv2": 175, + "atma": 176, + "drognan": 177, + "fara": 178, + "cow": 179, + "maggotbaby1": 180, + "maggotbaby2": 181, + "maggotbaby3": 182, + "maggotbaby4": 183, + "maggotbaby5": 184, + "camel": 185, + "blunderbore1": 186, + "blunderbore2": 187, + "blunderbore3": 188, + "blunderbore4": 189, + "maggotegg1": 190, + "maggotegg2": 191, + "maggotegg3": 192, + "maggotegg4": 193, + "maggotegg5": 194, + "act2male": 195, + "act2female": 196, + "act2child": 197, + "greiz": 198, + "elzix": 199, + "geglash": 200, + "jerhyn": 201, + "lysander": 202, + "act2guard1": 203, + "act2vendor1": 204, + "act2vendor2": 205, + "crownest1": 206, + "crownest2": 207, + "crownest3": 208, + "crownest4": 209, + "meshif1": 210, + "duriel": 211, + "bonefetish1": 212, + "bonefetish2": 213, + "bonefetish3": 214, + "bonefetish4": 215, + "bonefetish5": 216, + "darkguard1": 217, + "darkguard2": 218, + "darkguard3": 219, + "darkguard4": 220, + "darkguard5": 221, + "bloodmage1": 222, + "bloodmage2": 223, + "bloodmage3": 224, + "bloodmage4": 225, + "bloodmage5": 226, + "maggot": 227, + "sarcophagus": 228, + "radament": 229, + "firebeast": 230, + "iceglobe": 231, + "lightningbeast": 232, + "poisonorb": 233, + "flyingscimitar": 234, + "zealot1": 235, + "zealot2": 236, + "zealot3": 237, + "cantor1": 238, + "cantor2": 239, + "cantor3": 240, + "cantor4": 241, + "mephisto": 242, + "diablo": 243, + "cain2": 244, + "cain3": 245, + "cain4": 246, + "frogdemon1": 247, + "frogdemon2": 248, + "frogdemon3": 249, + "summoner": 250, + "tyrael1": 251, + "asheara": 252, + "hratli": 253, + "alkor": 254, + "ormus": 255, + "izual": 256, + "halbu": 257, + "tentacle1": 258, + "tentacle2": 259, + "tentacle3": 260, + "tentaclehead1": 261, + "tentaclehead2": 262, + "tentaclehead3": 263, + "meshif2": 264, + "cain5": 265, + "navi": 266, + "bloodraven": 267, + "bug": 268, + "scorpion": 269, + "rogue2": 270, + "roguehire": 271, + "rogue3": 272, + "gargoyletrap": 273, + "skmage_pois1": 274, + "skmage_pois2": 275, + "skmage_pois3": 276, + "skmage_pois4": 277, + "fetishshaman1": 278, + "fetishshaman2": 279, + "fetishshaman3": 280, + "fetishshaman4": 281, + "fetishshaman5": 282, + "larva": 283, + "maggotqueen1": 284, + "maggotqueen2": 285, + "maggotqueen3": 286, + "maggotqueen4": 287, + "maggotqueen5": 288, + "claygolem": 289, + "bloodgolem": 290, + "irongolem": 291, + "firegolem": 292, + "familiar": 293, + "act3male": 294, + "baboon6": 295, + "act3female": 296, + "natalya": 297, + "vilemother1": 298, + "vilemother2": 299, + "vilemother3": 300, + "vilechild1": 301, + "vilechild2": 302, + "vilechild3": 303, + "fingermage1": 304, + "fingermage2": 305, + "fingermage3": 306, + "regurgitator1": 307, + "regurgitator2": 308, + "regurgitator3": 309, + "doomknight1": 310, + "doomknight2": 311, + "doomknight3": 312, + "quillbear1": 313, + "quillbear2": 314, + "quillbear3": 315, + "quillbear4": 316, + "quillbear5": 317, + "snake": 318, + "parrot": 319, + "fish": 320, + "evilhole1": 321, + "evilhole2": 322, + "evilhole3": 323, + "evilhole4": 324, + "evilhole5": 325, + "trap_firebolt": 326, + "trap_horzmissile": 327, + "trap_vertmissile": 328, + "trap_poisoncloud": 329, + "trap_lightning": 330, + "act2guard2": 331, + "invisospawner": 332, + "diabloclone": 333, + "suckernest1": 334, + "suckernest2": 335, + "suckernest3": 336, + "suckernest4": 337, + "act2hire": 338, + "minispider": 339, + "boneprison1": 340, + "boneprison2": 341, + "boneprison3": 342, + "boneprison4": 343, + "bonewall": 344, + "councilmember1": 345, + "councilmember2": 346, + "councilmember3": 347, + "turret1": 348, + "turret2": 349, + "turret3": 350, + "hydra1": 351, + "hydra2": 352, + "hydra3": 353, + "trap_melee": 354, + "seventombs": 355, + "dopplezon": 356, + "valkyrie": 357, + "act2guard3": 358, + "act3hire": 359, + "megademon1": 360, + "megademon2": 361, + "megademon3": 362, + "necroskeleton": 363, + "necromage": 364, + "griswold": 365, + "compellingorb": 366, + "tyrael2": 367, + "darkwanderer": 368, + "trap-nova": 369, + "spiritmummy": 370, + "lightningspire": 371, + "firetower": 372, + "slinger1": 373, + "slinger2": 374, + "slinger3": 375, + "slinger4": 376, + "act2guard4": 377, + "act2guard5": 378, + "skmage_cold1": 379, + "skmage_cold2": 380, + "skmage_cold3": 381, + "skmage_cold4": 382, + "skmage_fire1": 383, + "skmage_fire2": 384, + "skmage_fire3": 385, + "skmage_fire4": 386, + "skmage_ltng1": 387, + "skmage_ltng2": 388, + "skmage_ltng3": 389, + "skmage_ltng4": 390, + "hellbovine": 391, + "window1": 392, + "window2": 393, + "slinger5": 394, + "slinger6": 395, + "fetishblow1": 396, + "fetishblow2": 397, + "fetishblow3": 398, + "fetishblow4": 399, + "fetishblow5": 400, + "mephistospirit": 401, + "smith": 402, + "trappedsoul1": 403, + "trappedsoul2": 404, + "jamella": 405, + "izualghost": 406, + "fetish11": 407, + "malachai": 408, + "hephasto": 409, + "wakeofdestruction": 410, + "chargeboltsentry": 411, + "lightningsentry": 412, + "bladecreeper": 413, + "invisopet": 414, + "infernosentry": 415, + "deathsentry": 416, + "shadowwarrior": 417, + "shadowmaster": 418, + "druidhawk": 419, + "spiritwolf": 420, + "fenris": 421, + "spiritofbarbs": 422, + "heartofwolverine": 423, + "oaksage": 424, + "plaguepoppy": 425, + "cycleoflife": 426, + "vinecreature": 427, + "druidbear": 428, + "eagle": 429, + "wolf": 430, + "bear": 431, + "barricadedoor1": 432, + "barricadedoor2": 433, + "prisondoor": 434, + "barricadetower": 435, + "reanimatedhorde1": 436, + "reanimatedhorde2": 437, + "reanimatedhorde3": 438, + "reanimatedhorde4": 439, + "reanimatedhorde5": 440, + "siegebeast1": 441, + "siegebeast2": 442, + "siegebeast3": 443, + "siegebeast4": 444, + "siegebeast5": 445, + "snowyeti1": 446, + "snowyeti2": 447, + "snowyeti3": 448, + "snowyeti4": 449, + "wolfrider1": 450, + "wolfrider2": 451, + "wolfrider3": 452, + "minion1": 453, + "minion2": 454, + "minion3": 455, + "minion4": 456, + "minion5": 457, + "minion6": 458, + "minion7": 459, + "minion8": 460, + "suicideminion1": 461, + "suicideminion2": 462, + "suicideminion3": 463, + "suicideminion4": 464, + "suicideminion5": 465, + "suicideminion6": 466, + "suicideminion7": 467, + "suicideminion8": 468, + "succubus1": 469, + "succubus2": 470, + "succubus3": 471, + "succubus4": 472, + "succubus5": 473, + "succubuswitch1": 474, + "succubuswitch2": 475, + "succubuswitch3": 476, + "succubuswitch4": 477, + "succubuswitch5": 478, + "overseer1": 479, + "overseer2": 480, + "overseer3": 481, + "overseer4": 482, + "overseer5": 483, + "minionspawner1": 484, + "minionspawner2": 485, + "minionspawner3": 486, + "minionspawner4": 487, + "minionspawner5": 488, + "minionspawner6": 489, + "minionspawner7": 490, + "minionspawner8": 491, + "imp1": 492, + "imp2": 493, + "imp3": 494, + "imp4": 495, + "imp5": 496, + "catapult1": 497, + "catapult2": 498, + "catapult3": 499, + "catapult4": 500, + "frozenhorror1": 501, + "frozenhorror2": 502, + "frozenhorror3": 503, + "frozenhorror4": 504, + "frozenhorror5": 505, + "bloodlord1": 506, + "bloodlord2": 507, + "bloodlord3": 508, + "bloodlord4": 509, + "bloodlord5": 510, + "larzuk": 511, + "drehya": 512, + "malah": 513, + "nihlathak": 514, + "qual_kehk": 515, + "catapultspotter1": 516, + "catapultspotter2": 517, + "catapultspotter3": 518, + "catapultspotter4": 519, + "cain6": 520, + "tyrael3": 521, + "act5barb1": 522, + "act5barb2": 523, + "barricadewall1": 524, + "barricadewall2": 525, + "nihlathakboss": 526, + "drehyaiced": 527, + "evilhut": 528, + "deathmauler1": 529, + "deathmauler2": 530, + "deathmauler3": 531, + "deathmauler4": 532, + "deathmauler5": 533, + "act5pow": 534, + "act5barb3": 535, + "act5barb4": 536, + "ancientstatue1": 537, + "ancientstatue2": 538, + "ancientstatue3": 539, + "ancientbarb1": 540, + "ancientbarb2": 541, + "ancientbarb3": 542, + "baalthrone": 543, + "baalcrab": 544, + "baaltaunt": 545, + "putriddefiler1": 546, + "putriddefiler2": 547, + "putriddefiler3": 548, + "putriddefiler4": 549, + "putriddefiler5": 550, + "painworm1": 551, + "painworm2": 552, + "painworm3": 553, + "painworm4": 554, + "painworm5": 555, + "bunny": 556, + "baalhighpriest": 557, + "venomlord": 558, + "baalcrabstairs": 559, + "act5hire1": 560, + "act5hire2": 561, + "baaltentacle1": 562, + "baaltentacle2": 563, + "baaltentacle3": 564, + "baaltentacle4": 565, + "baaltentacle5": 566, + "injuredbarb1": 567, + "injuredbarb2": 568, + "injuredbarb3": 569, + "baalclone": 570, + "baalminion1": 571, + "baalminion2": 572, + "baalminion3": 573, + "worldstoneeffect": 574, + "sk_archer6": 575, + "sk_archer7": 576, + "sk_archer8": 577, + "sk_archer9": 578, + "sk_archer10": 579, + "bighead6": 580, + "bighead7": 581, + "bighead8": 582, + "bighead9": 583, + "bighead10": 584, + "goatman6": 585, + "goatman7": 586, + "goatman8": 587, + "goatman9": 588, + "goatman10": 589, + "foulcrow5": 590, + "foulcrow6": 591, + "foulcrow7": 592, + "foulcrow8": 593, + "clawviper6": 594, + "clawviper7": 595, + "clawviper8": 596, + "clawviper9": 597, + "clawviper10": 598, + "sandraider6": 599, + "sandraider7": 600, + "sandraider8": 601, + "sandraider9": 602, + "sandraider10": 603, + "deathmauler6": 604, + "quillrat6": 605, + "quillrat7": 606, + "quillrat8": 607, + "vulture5": 608, + "thornhulk5": 609, + "slinger7": 610, + "slinger8": 611, + "slinger9": 612, + "cr_archer6": 613, + "cr_archer7": 614, + "cr_lancer6": 615, + "cr_lancer7": 616, + "cr_lancer8": 617, + "blunderbore5": 618, + "blunderbore6": 619, + "skmage_fire5": 620, + "skmage_fire6": 621, + "skmage_ltng5": 622, + "skmage_ltng6": 623, + "skmage_cold5": 624, + "skmage_pois5": 625, + "skmage_pois6": 626, + "pantherwoman5": 627, + "pantherwoman6": 628, + "sandleaper6": 629, + "sandleaper7": 630, + "wraith6": 631, + "wraith7": 632, + "wraith8": 633, + "succubus6": 634, + "succubus7": 635, + "succubuswitch6": 636, + "succubuswitch7": 637, + "succubuswitch8": 638, + "willowisp5": 639, + "willowisp6": 640, + "willowisp7": 641, + "fallen6": 642, + "fallen7": 643, + "fallen8": 644, + "fallenshaman6": 645, + "fallenshaman7": 646, + "fallenshaman8": 647, + "skeleton6": 648, + "skeleton7": 649, + "batdemon6": 650, + "batdemon7": 651, + "bloodlord6": 652, + "bloodlord7": 653, + "scarab6": 654, + "scarab7": 655, + "fetish6": 656, + "fetish7": 657, + "fetish8": 658, + "fetishblow6": 659, + "fetishblow7": 660, + "fetishblow8": 661, + "fetishshaman6": 662, + "fetishshaman7": 663, + "fetishshaman8": 664, + "baboon7": 665, + "baboon8": 666, + "unraveler6": 667, + "unraveler7": 668, + "unraveler8": 669, + "unraveler9": 670, + "zealot4": 671, + "zealot5": 672, + "cantor5": 673, + "cantor6": 674, + "vilemother4": 675, + "vilemother5": 676, + "vilechild4": 677, + "vilechild5": 678, + "sandmaggot6": 679, + "maggotbaby6": 680, + "maggotegg6": 681, + "minion9": 682, + "minion10": 683, + "minion11": 684, + "arach6": 685, + "megademon4": 686, + "megademon5": 687, + "imp6": 688, + "imp7": 689, + "bonefetish6": 690, + "bonefetish7": 691, + "fingermage4": 692, + "fingermage5": 693, + "regurgitator4": 694, + "vampire6": 695, + "vampire7": 696, + "vampire8": 697, + "reanimatedhorde6": 698, + "dkfig1": 699, + "dkfig2": 700, + "dkmag1": 701, + "dkmag2": 702, + "mummy6": 703, + "Uber_Mephisto": 704, + "Uber_Baal": 705, + "Uber_Izual": 706, + "Lilith": 707, + "Uber_Duriel": 708, + "Pandemonium_Diablo": 709 + }; \ No newline at end of file diff --git a/d2bs/kolbot/libs/common/Loader.js b/d2bs/kolbot/libs/common/Loader.js index ebdf0e2ee..7ccbdbf2e 100644 --- a/d2bs/kolbot/libs/common/Loader.js +++ b/d2bs/kolbot/libs/common/Loader.js @@ -25,8 +25,66 @@ var Loader = { } }, + // see http://stackoverflow.com/questions/728360/copying-an-object-in-javascript#answer-728694 + clone: function (obj) { + var i, copy, attr; + + // Handle the 3 simple types, and null or undefined + if (null === obj || "object" !== typeof obj) { + return obj; + } + + // Handle Date + if (obj instanceof Date) { + copy = new Date(); + + copy.setTime(obj.getTime()); + + return copy; + } + + // Handle Array + if (obj instanceof Array) { + copy = []; + + for (i = 0; i < obj.length; i += 1) { + copy[i] = this.clone(obj[i]); + } + + return copy; + } + + // Handle Object + if (obj instanceof Object) { + copy = {}; + + for (attr in obj) { + if (obj.hasOwnProperty(attr)) { + copy[attr] = this.clone(obj[attr]); + } + } + + return copy; + } + + throw new Error("Unable to copy obj! Its type isn't supported."); + }, + + copy: function (from, to) { + var i; + + for (i in from) { + if (from.hasOwnProperty(i)) { + to[i] = this.clone(from[i]); + } + } + }, + loadScripts: function () { - var i, townCheck; + var i, townCheck, reconfiguration, + unmodifiedConfig = {}; + + this.copy(Config, unmodifiedConfig); if (!this.scriptList.length) { showConsole(); @@ -34,33 +92,52 @@ 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 && Scripts[i]) { - include("bots/" + i + ".js"); - - if (typeof (global[i]) === "function") { - if (i !== "Test") { - try { - townCheck = Town.goToTown(); - } catch (e1) { - print("ÿc1Loader: Failed to go to town, skipping to next script."); + 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); } - } else { - townCheck = true; - } - if (townCheck) { - try { - print("ÿc2Starting script: ÿc9" + i); - global[i](); - } catch (e) { - showConsole(); - print("ÿc1Error in ÿc0" + i + " ÿc1(" + e.fileName.substring(e.fileName.lastIndexOf("\\") + 1, e.fileName.length) + " line ÿc1" + e.lineNumber + ") : ÿc1" + e.message); + 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 (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); + } + + global[i](); + + if (reconfiguration) { + print("ÿc2Reverting back unmodified config properties."); + this.copy(unmodifiedConfig, Config); + } + } + } else { + throw new Error("Invalid script function name"); + } + } catch (error) { + Misc.errorReport(error, i); + } } } } else { - print("ÿc1Loader: Error in script, skipping;"); + Misc.errorReport("ÿc1Script " + i + " doesn't exist."); } } } diff --git a/d2bs/kolbot/libs/common/Misc.js b/d2bs/kolbot/libs/common/Misc.js index 16ee03cff..71e2d063e 100644 --- a/d2bs/kolbot/libs/common/Misc.js +++ b/d2bs/kolbot/libs/common/Misc.js @@ -5,6 +5,217 @@ */ var Skill = { + usePvpRange: false, + + getRange: function (skillId) { + switch (skillId) { + case Skills.common.Attack: // Normal Attack + return Attack.usingBow() ? 20 : 3; + case Skills.Amazon.Jab: // Jab + case Skills.Amazon.Power_Strike: // Power Strike + case Skills.Amazon.Impale: // Impale + case Skills.Amazon.Fend: // Fend + case Skills.Amazon.Lightning_Strike: // Lightning Strike + case Skills.Amazon.Poison_Javelin: // Poison Dagger + case Skills.Paladin.Sacrifice: // Sacrifice + case Skills.Paladin.Smite: // Smite + case Skills.Paladin.Zeal: // Zeal + case Skills.Paladin.Blessed_Hammer: // Blessed Hammer + case Skills.Paladin.Conversion: // Conversion + case Skills.Barbarian.Bash: // Bash + case Skills.Barbarian.Double_Swing: // Double Swing + case Skills.Barbarian.Stun: // Stun + case Skills.Barbarian.Concentrate: // Concentrate + case Skills.Barbarian.Frenzy: // Frenzy + case Skills.Barbarian.Berserk: // Berserk + case Skills.Druid.Feral_Rage: // Feral Rage + case Skills.Druid.Maul: // Maul + case Skills.Druid.Rabies: // Rabies + case Skills.Druid.Fire_Claws: // Fire Claws + case Skills.Druid.Hunger: // Hunger + case Skills.Druid.Fury: // Fury + case Skills.Assassin.Dragon_Talon: // Dragon Talon + case Skills.Assassin.Dragon_Claw: // Dragon Claw + case Skills.Assassin.Dragon_Tail: // Dragon Tail + return 3; + case Skills.Barbarian.Battle_Cry: // Battle Cry + case Skills.Barbarian.War_Cry: // War Cry + return 4; + case Skills.Sorceress.Frost_Nova: // Frost Nova + case Skills.Druid.Twister: // Twister + case Skills.Druid.Tornado: // Tornado + case 500: // Summoner + return 5; + case Skills.Sorceress.Charged_Bolt: // Charged Bolt + return 6; + case Skills.Sorceress.Nova: // Nova + case Skills.Barbarian.Whirlwind: // Whirlwind + return 7; + case Skills.Necromancer.Poison_Nova: // Poison Nova + return 8; + case Skills.Paladin.Holy_Bolt: // Holy Bolt + case Skills.Paladin.Charge: // Charge + case Skills.Barbarian.Howl: // Howl + case Skills.Barbarian.Leap: // Leap + case Skills.Druid.Firestorm: // Firestorm + case Skills.Druid.Molten_Boulder: // Molten Boulder + case Skills.Druid.Arctic_Blast: // Arctic Blast + case Skills.Druid.Shock_Wave: // Shock Wave + return 10; + case Skills.Sorceress.Frozen_Orb: // Frozen Orb + case Skills.Necromancer.Teeth: // Teeth + case Skills.Druid.Eruption: // Fissure + case Skills.Druid.Volcano: // Volcano + case Skills.Assassin.Fire_Trauma: // Fire Blast + case Skills.Assassin.Shock_Field: // Shock Web + case Skills.Assassin.Blade_Sentinel: // Blade Sentinel + case Skills.Assassin.Blade_Fury: // Blade Fury + return 15; + case Skills.Paladin.Fist_of_the_Heavens: // Fist of the Heavens + case Skills.Assassin.Psychic_Hammer: // Psychic Hammer + case Skills.Assassin.Dragon_Flight: // Dragon Flight + return 20; + // Variable range + case Skills.Sorceress.Static_Field: // Static Field + if (me.gametype === GameType.Expansion) { + return Math.floor((me.getSkill(Skills.Sorceress.Static_Field, 1) + 4) * 2 / 3); + } + + return 20; + case Skills.Sorceress.Lightning: // Lightning + case Skills.Necromancer.Bone_Spear: // Bone Spear + case Skills.Necromancer.Bone_Spirit: // Bone Spirit + if (this.usePvpRange) { + return 40; + } + + return 15; + case Skills.Amazon.Charged_Strike: // Charged Strike + case Skills.Sorceress.Fire_Ball: + case Skills.Sorceress.Fire_Wall: + case Skills.Sorceress.Chain_Lightning: + case Skills.Sorceress.Meteor: + case Skills.Sorceress.Blizzard: + case Skills.Assassin.Mind_Blast: // 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 Skills.Amazon.Magic_Arrow: + case Skills.Amazon.Fire_Arrow: + case Skills.Amazon.Critical_Strike: + case Skills.Amazon.Jab: + case Skills.Amazon.Cold_Arrow: + case Skills.Amazon.Multiple_Shot: + case Skills.Amazon.Dodge: + case Skills.Amazon.Power_Strike: + case Skills.Amazon.Poison_Javelin: + case Skills.Amazon.Exploding_Arrow: + case Skills.Amazon.Avoid: + case Skills.Amazon.Impale: + case Skills.Amazon.Lightning_Bolt: + case Skills.Amazon.Ice_Arrow: + case Skills.Amazon.Guided_Arrow: + case Skills.Amazon.Penetrate: + case Skills.Amazon.Charged_Strike: + case Skills.Amazon.Plague_Javelin: + case Skills.Amazon.Strafe: + case Skills.Amazon.Immolation_Arrow: + case Skills.Amazon.Evade: + case Skills.Amazon.Fend: + case Skills.Amazon.Freezing_Arrow: + case Skills.Amazon.Pierce: + case Skills.Amazon.Lightning_Strike: + case Skills.Amazon.Lightning_Fury: + case Skills.Sorceress.Fire_Bolt: + case Skills.Sorceress.Warmth: + case Skills.Sorceress.Charged_Bolt: + case Skills.Sorceress.Ice_Bolt: + case Skills.Sorceress.Inferno: + case Skills.Sorceress.Ice_Blast: + case Skills.Sorceress.Fire_Ball: + case Skills.Sorceress.Lightning: + case Skills.Sorceress.Chain_Lightning: + case Skills.Sorceress.Glacial_Spike: + case Skills.Sorceress.Fire_Mastery: + case Skills.Sorceress.Lightning_Mastery: + case Skills.Sorceress.Frozen_Orb: + case Skills.Sorceress.Cold_Mastery: + case Skills.Necromancer.Teeth: + case Skills.Necromancer.Poison_Dagger: + case Skills.Necromancer.Golem_Mastery: + case Skills.Necromancer.Bone_Spear: + case Skills.Necromancer.Summon_Resist: + case Skills.Necromancer.Bone_Spirit: + case Skills.Paladin.Holy_Bolt: + case Skills.Paladin.Charge: + case Skills.Paladin.Vengeance: + case Skills.Paladin.Blessed_Hammer: + case Skills.Paladin.Fist_of_the_Heavens: + case Skills.Barbarian.Leap: + case Skills.Barbarian.Double_Throw: + case Skills.Barbarian.Leap_Attack: + case Skills.Barbarian.Whirlwind: + case Skills.Druid.Firestorm: + case Skills.Druid.Molten_Boulder: + case Skills.Druid.Arctic_Blast: + case Skills.Druid.Twister: + case Skills.Druid.Shock_Wave: + case Skills.Druid.Tornado: + case Skills.Assassin.Fire_Trauma: + case Skills.Assassin.Tiger_Strike: + case Skills.Assassin.Shock_Field: + case Skills.Assassin.Blade_Sentinel: + case Skills.Assassin.Fists_of_Fire: + case Skills.Assassin.Weapon_Block: + case Skills.Assassin.Cobra_Strike: + case Skills.Assassin.Blade_Fury: + case Skills.Assassin.Claws_of_Thunder: + case Skills.Assassin.Blades_of_Ice: + case Skills.Assassin.Dragon_Flight: + return 1; + case Skills.common.Attack: // Normal Attack + case Skills.Paladin.Sacrifice: // Sacrifice + case Skills.Paladin.Smite: // Smite + case Skills.Paladin.Zeal: // Zeal + case Skills.Paladin.Conversion: // Conversion + case Skills.Barbarian.Bash: // Bash + case Skills.Barbarian.Double_Swing: // Double Swing + case Skills.Barbarian.Stun: // Stun + case Skills.Barbarian.Concentrate: // Concentrate + case Skills.Barbarian.Frenzy: // Frenzy + case Skills.Barbarian.Berserk: // Berserk + case Skills.Druid.Feral_Rage: // Feral Rage + case Skills.Druid.Maul: // Maul + case Skills.Druid.Rabies: // Rabies + case Skills.Druid.Fire_Claws: // Fire Claws + case Skills.Druid.Hunger: // Hunger + case Skills.Druid.Fury: // Fury + case Skills.Assassin.Dragon_Talon: // Dragon Talon + case Skills.Assassin.Dragon_Claw: // Dragon Claw + case Skills.Assassin.Dragon_Tail: // Dragon Tail + return 2; // Shift bypass + } + + // Every other skill + return 0; + }, + + charges: [], + // Cast a skill on self, Unit or coords cast: function (skillId, hand, x, y) { if (me.inTown && !this.townSkill(skillId)) { @@ -15,72 +226,116 @@ var Skill = { return false; } - if (!arguments.length) { + if (!this.wereFormCheck(skillId)) { + return false; + } + + // No mana to cast + if (this.getManaCost(skillId) > me.mp) { + // Maybe delay on ALL skills that we don't have enough mana for? + if (Config.AttackSkill.concat([Skills.Sorceress.Static_Field, Skills.Sorceress.Teleport]).concat(Config.LowManaSkill).indexOf(skillId) > -1) { + delay(300); + } + + return false; + } + + if (skillId === undefined) { throw new Error("Skill.cast: Must supply a skill ID"); } var i, n, clickType, shift; - if (arguments.length === 1) { + if (hand === undefined) { hand = 0; } - if (arguments.length < 3) { + if (x === undefined) { x = me.x; - y = me.y; } - switch (hand) { - case 0: - clickType = 3; - shift = 0; - break; - case 1: - clickType = 0; - shift = 1; - break; - case 2: // For melee skills that don't need shift - clickType = 0; - shift = 0; - break; + if (y === undefined) { + y = me.y; } if (!this.setSkill(skillId, hand)) { return false; } -MainLoop: - for (n = 0; n < 3; n += 1) { - if (arguments.length === 3) { - clickMap(clickType, shift, x); - } else { - clickMap(clickType, shift, x, y); - } + if (Config.PacketCasting > 1) { + switch (typeof x) { + case "number": + Packet.castSkill(hand, x, y); + delay(250); - delay(30); + break; + case "object": + Packet.unitCast(hand, x); + delay(250); - if (arguments.length === 3) { - clickMap(clickType + 2, shift, x); - } else { - clickMap(clickType + 2, shift, x, y); + break; + } + } else { + switch (hand) { + case 0: // Right hand + No Shift + clickType = 3; + shift = 0; + + break; + case 1: // Left hand + Shift + clickType = 0; + shift = 1; + + break; + case 2: // Left hand + No Shift + clickType = 0; + shift = 0; + + break; + case 3: // Right hand + Shift + clickType = 3; + shift = 1; + + break; } - for (i = 0; i < 4; i += 1) { - if (me.attacking) { - break MainLoop; +MainLoop: + for (n = 0; n < 3; n += 1) { + if (typeof x === "object") { + clickMap(clickType, shift, x); + } else { + clickMap(clickType, shift, x, y); + } + + delay(20); + + if (typeof x === "object") { + clickMap(clickType + 2, shift, x); + } else { + clickMap(clickType + 2, shift, x, y); } - delay(40); + for (i = 0; i < 8; i += 1) { + if (me.attacking) { + break MainLoop; + } + + delay(20); + } } - } - while (me.attacking) { - delay(10); + while (me.attacking) { + delay(10); + } } if (this.isTimed(skillId)) { // account for lag, state 121 doesn't kick in immediately for (i = 0; i < 10; i += 1) { - if (me.getState(121)) { + if ([4, 9].indexOf(me.mode) > -1) { + break; + } + + if (me.getState(States.SKILLDELAY)) { break; } @@ -93,17 +348,28 @@ MainLoop: // Put a skill on desired slot setSkill: function (skillId, hand) { + // Check if the skill is already set + if (me.getSkill(hand === 0 ? Skills.common.Throw : Skills.common.Unsummon) === skillId) { + return true; + } + if (!me.getSkill(skillId, 1)) { return false; } - if (arguments.length < 2) { + 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)) { @@ -113,14 +379,357 @@ MainLoop: return false; }, + // Charged skill + 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 this.charges[i]; + } + } + + return false; + }, + // Timed skills isTimed: function (skillId) { - return [15, 25, 27, 51, 56, 59, 62, 64, 121, 225, 223, 228, 229, 234, 244, 247, 249, 250, 256, 268, 275, 277, 279].indexOf(skillId) > -1; + return [Skills.Amazon.Poison_Javelin, Skills.Amazon.Plague_Javelin, Skills.Amazon.Immolation_Arrow, + Skills.Sorceress.Fire_Wall, Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard, Skills.Sorceress.Hydra, Skills.Sorceress.Frozen_Orb, + Skills.Paladin.Fist_of_the_Heavens, + Skills.Druid.Firestorm, Skills.Druid.Wearwolf, Skills.Druid.Wearbear, Skills.Druid.Molten_Boulder, Skills.Druid.Eruption, Skills.Druid.Volcano, Skills.Druid.Summon_Grizzly, Skills.Druid.Armageddon, Skills.Druid.Hurricane, + Skills.Assassin.Shock_Field, Skills.Assassin.Shadow_Warrior, Skills.Assassin.Dragon_Flight, Skills.Assassin.Blade_Shield, Skills.Assassin.Shadow_Master] + .indexOf(skillId) > -1; + }, + + // Wereform skill check + wereFormCheck: function (skillId) { + if (!me.getState(States.WOLF) && !me.getState(States.BEAR)) { + return true; + } + + // Can be cast by both + if ([Skills.common.Attack, Skills.common.Kick, Skills.Druid.Raven, Skills.Druid.Plague_Poppy, Skills.Druid.Oak_Sage, Skills.Druid.Summon_Spirit_Wolf, Skills.Druid.Cycle_of_Life, Skills.Druid.Heart_of_Wolverine, + Skills.Druid.Summon_Fenris, Skills.Druid.Fire_Claws, Skills.Druid.Vines, Skills.Druid.Hunger, Skills.Druid.Spirit_of_Barbs, Skills.Druid.Summon_Grizzly, Skills.Druid.Armageddon].indexOf(skillId) > -1) { + return true; + } + + // Can be cast by werewolf only + if (me.getState(States.WOLF) && [Skills.Druid.Wearwolf, Skills.Druid.Feral_Rage, Skills.Druid.Rabies, Skills.Druid.Fury].indexOf(skillId) > -1) { + return true; + } + + // Can be cast by werebear only + if (me.getState(States.BEAR) && [Skills.Druid.Wearbear, Skills.Druid.Maul, Skills.Druid.Shock_Wave].indexOf(skillId) > -1) { + return true; + } + + return false; }, // Skills that cn be cast in town townSkill: function (skillId) { - 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; + return [Skills.Amazon.Valkyrie, Skills.Sorceress.Frozen_Armor, Skills.Sorceress.Telekinesis, Skills.Sorceress.Shiver_Armor, Skills.Sorceress.Enchant, Skills.Sorceress.Energy_Shield, + Skills.Sorceress.Chilling_Armor, Skills.Necromancer.Bone_Armor, Skills.Necromancer.Clay_Golem, Skills.Necromancer.BloodGolem, Skills.Necromancer.FireGolem, Skills.Paladin.Holy_Shield, + Skills.Druid.Raven, Skills.Druid.Plague_Poppy, Skills.Druid.Oak_Sage, Skills.Druid.Summon_Spirit_Wolf, Skills.Druid.Cyclone_Armor, Skills.Druid.Heart_of_Wolverine, + Skills.Druid.Summon_Fenris, Skills.Druid.Spirit_of_Barbs, Skills.Druid.Summon_Grizzly, Skills.Assassin.Quickness, Skills.Assassin.Fade, Skills.Assassin.Shadow_Warrior, + Skills.Assassin.Blade_Shield, Skills.Assassin.Venom, Skills.Assassin.Shadow_Master].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(BaseStat.skills, skillId, "lvlmana") === 65535 ? -1 : getBaseStat(BaseStat.skills, skillId, "lvlmana"), // Correction for skills that need less mana with levels (kolton) + ret = Math.max((getBaseStat(BaseStat.skills, skillId, "mana") + lvlmana * (skillLvl - 1)) * (effectiveShift[getBaseStat(BaseStat.skills, skillId, "manashift")] / 256), getBaseStat(3, skillId, "minmana")); + + if (!this.manaCostList.hasOwnProperty(skillId)) { + this.manaCostList[skillId] = ret; + } + + return ret; + } +}; + +var Item = { + hasTier: function (item) { + return Config.AutoEquip && NTIP.GetTier(item) > 0; + }, + + canEquip: function (item) { + if (item.type !== NTItemTypes.gold) { // Not an item + return false; + } + + if (!item.getFlag(ItemFlags.isIdentified)) { // Unid item + return false; + } + + if (item.getStat(Stats.item_levelreq) > me.getStat(Stats.level) || item.dexreq > me.getStat(Stats.dexterity) || item.strreq > me.getStat(Stats.strength)) { // 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; + } + + // Already equipped in the right slot + if (item.mode === ItemModes.Item_equipped_self_or_merc && item.bodylocation === bodyLoc) { + return true; + } + + var i, cursorItem; + + if (item.location === ItemLocation.Stash) { + 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 NTItemTypes.shield: // Shield + case NTItemTypes.auricshields: // Auric Shields + bodyLoc = ItemBodyLocation.LEFT_ARM; + + break; + case NTItemTypes.armor: // Armor + bodyLoc = ItemBodyLocation.TORSO; + + break; + case NTItemTypes.bowquiver: // Arrows + case NTItemTypes.crossbowquiver: // Bolts + bodyLoc = ItemBodyLocation.LEFT_ARM; + + break; + case NTItemTypes.ring: // Ring + bodyLoc = [ItemBodyLocation.RIGHT_RING, ItemBodyLocation.LEFT_RING]; + + break; + case NTItemTypes.amulet: // Amulet + bodyLoc = ItemBodyLocation.NECK; + + break; + case NTItemTypes.boots: // Boots + bodyLoc = ItemBodyLocation.FEET; + + break; + case NTItemTypes.gloves: // Gloves + bodyLoc = ItemBodyLocation.GLOVES; + + break; + case NTItemTypes.belt: // Belt + bodyLoc = ItemBodyLocation.BELT; + + break; + case NTItemTypes.helm: // Helm + case NTItemTypes.primalhelm: // Barb Helm + case NTItemTypes.circlet: // Circlet + bodyLoc = ItemBodyLocation.HEAD; + + break; + case NTItemTypes.scepter: // + case NTItemTypes.wand: // + case NTItemTypes.staff: // + case NTItemTypes.bow: // + case NTItemTypes.axe: // + case NTItemTypes.club: // + case NTItemTypes.sword: // + case NTItemTypes.hammer: // + case NTItemTypes.knife: // + case NTItemTypes.spear: // + case NTItemTypes.polearm: // + case NTItemTypes.crossbow: // + case NTItemTypes.mace: // + case NTItemTypes.throwingknife: // + case NTItemTypes.throwingaxe: // + case NTItemTypes.javelin: // + case NTItemTypes.handtohand: // Handtohand (Assasin Claw) + case NTItemTypes.orb: // + case NTItemTypes.voodooheads: // + case NTItemTypes.pelt: // + case NTItemTypes.amazonbow: // + case NTItemTypes.amazonspear: // + case NTItemTypes.amazonjavelin: // + case NTItemTypes.assassinclaw: // + bodyLoc = ItemBodyLocation.RIGHT_ARM; + + break; + default: + return false; + } + + if (typeof bodyLoc === "number") { + bodyLoc = [bodyLoc]; + } + + return bodyLoc; + }, + + 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(ItemFlags.isIdentified))) { + return true; + } + } + } + + // 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 !== ItemClassIds.Khalims_Will) { // khalim's will adjustment + if (!items[0].getFlag(ItemFlags.isIdentified)) { // unid + tome = me.findItem(ItemClassIds.Tome_Of_Identify, 0, ItemLocation.Inventory); + + if (tome && tome.getStat(Stats.quantity) > 0) { + if (items[0].location === ItemLocation.Stash) { + 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; } }; @@ -131,11 +740,16 @@ var Misc = { throw new Error("Misc.click: Needs at least 2 arguments."); } + while (!me.gameReady) { + delay(100); + } + switch (arguments.length) { case 2: clickMap(button, shift, me.x, me.y); delay(20); clickMap(button + 2, shift, me.x, me.y); + break; case 3: if (typeof (x) !== "object") { @@ -145,11 +759,13 @@ var Misc = { clickMap(button, shift, x); delay(20); clickMap(button + 2, shift, x); + break; case 4: clickMap(button, shift, x, y); delay(20); clickMap(button + 2, shift, x, y); + break; } @@ -158,6 +774,14 @@ var Misc = { // Check if a player is in your party inMyParty: function (name) { + if (me.name === name) { + return true; + } + + while (!me.gameReady) { + delay(100); + } + var player, myPartyId; try { @@ -190,21 +814,59 @@ var Misc = { return false; }, - // OPen a chest Unit + // Get number of players within getUnit distance + getNearbyPlayerCount: function () { + var count = 0, + player = getUnit(UnitType.Player); + + 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) { - if (!unit || unit.mode || unit.x === 12526 || unit.x === 12565) { // Skip invalid, opened and Countess chests + // Skip invalid and Countess chests + if (!unit || unit.x === 12526 || unit.x === 12565) { return false; } - if (me.classid !== 6 && unit.islocked && !me.findItem("key", 0, 3)) { // locked chest, no keys + // already open + if (unit.mode) { + return true; + } + + // locked chest, no keys + if (me.classid !== ClassID.Assassin && unit.islocked && !me.findItem(ItemClassIds.Key, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory)) { return false; } var i, tick; for (i = 0; i < 3; i += 1) { - if (getDistance(me, unit) < 4 || Pather.moveToUnit(unit)) { - unit.interact(); + 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(); @@ -218,54 +880,217 @@ var Misc = { } } + if (!me.idle) { + Misc.click(0, 0, me.x, me.y); // Click to stop walking in case we got stuck + } + return false; }, // Open all chests that have preset units in an area - openChestsInArea: function (area) { + openChestsInArea: function (area, chestIds) { + var i, coords, presetUnits; + if (!area) { area = me.area; } - var chest, - presetUnits = getPresetUnits(area), - chestIds = [5, 6, 87, 92, 104, 105, 106, 107, 143, 140, 141, 144, 146, 147, 148, 176, 177, 181, 183, 198, 240, 241, 242, 243, 329, 330, 331, 332, 333, 334, 335, - 336, 354, 355, 356, 371, 387, 389, 390, 391, 397, 405, 406, 407, 413, 420, 424, 425, 430, 431, 432, 433, 454, 455, 501, 502, 504, 505, 580, 581]; + // testing + if (area !== me.area) { + Pather.journeyTo(area); + } + + coords = []; + presetUnits = getPresetUnits(area, UnitType.Object); + + if (!chestIds) { + chestIds = [ + 5, 6, 87, 104, 105, 106, 107, 143, 140, 141, 144, 146, 147, 148, 176, 177, 181, 183, 198, 240, 241, + 242, 243, 329, 330, 331, 332, 333, 334, 335, 336, 354, 355, 356, 371, 387, 389, 390, 391, 397, 405, + 406, 407, 413, 420, 424, 425, 430, 431, 432, 433, 454, 455, 501, 502, 504, 505, 580, 581 + ]; + } if (!presetUnits) { return false; } while (presetUnits.length > 0) { - presetUnits.sort(Sort.presetUnits); - if (chestIds.indexOf(presetUnits[0].id) > -1) { - Pather.moveToUnit(presetUnits[0], 2, 0); - - chest = getUnit(2); - - if (chest) { - do { - if (chestIds.indexOf(chest.classid) > -1 && getDistance(me, chest) < 5 && this.openChest(chest)) { - Pickit.pickItems(); - } - } while (chest.getNext()); - } + coords.push({ + x: presetUnits[0].roomx * 5 + presetUnits[0].x, + y: presetUnits[0].roomy * 5 + presetUnits[0].y + }); } presetUnits.shift(); } + while (coords.length) { + coords.sort(Sort.units); + Pather.moveToUnit(coords[0], 1, 2); + this.openChests(20); + + for (i = 0; i < coords.length; i += 1) { + if (getDistance(coords[i].x, coords[i].y, coords[0].x, coords[0].y) < 20) { + coords.shift(); + } + } + } + + return true; + }, + + openChests: function (range) { + var unit, + unitList = [], + containers = ["chest", "chest3", "armorstand", "weaponrack"]; + + if (!range) { + range = 15; + } + + // Testing all container code + if (Config.OpenChests === 2) { + containers = [ + "chest", "loose rock", "hidden stash", "loose boulder", "corpseonstick", "casket", "armorstand", "weaponrack", "barrel", "holeanim", "tomb2", + "tomb3", "roguecorpse", "ratnest", "corpse", "goo pile", "largeurn", "urn", "chest3", "jug", "skeleton", "guardcorpse", "sarcophagus", "object2", + "cocoon", "basket", "stash", "hollow log", "hungskeleton", "pillar", "skullpile", "skull pile", "jar3", "jar2", "jar1", "bonechest", "woodchestl", + "woodchestr", "barrel wilderness", "burialchestr", "burialchestl", "explodingchest", "chestl", "chestr", "groundtomb", "icecavejar1", "icecavejar2", + "icecavejar3", "icecavejar4", "deadperson", "deadperson2", "evilurn", "tomb1l", "tomb3l", "groundtombl" + ]; + } + + unit = getUnit(UnitType.Object); + + if (unit) { + do { + if (unit.name && unit.mode === ObjectModes.Neutral && getDistance(me.x, me.y, unit.x, unit.y) <= range && containers.indexOf(unit.name.toLowerCase()) > -1) { + unitList.push(copyUnit(unit)); + } + } while (unit.getNext()); + } + + while (unitList.length > 0) { + unitList.sort(Sort.units); + + unit = unitList.shift(); + + if (unit && (Pather.useTeleport || !checkCollision(me, unit, 0x4)) && this.openChest(unit)) { + Pickit.pickItems(); + } + } + + return true; + }, + + shrineStates: false, + + scanShrines: function (range) { + if (!Config.ScanShrines.length) { + return false; + } + + if (!range) { + range = Pather.useTeleport ? 25 : 15; + } + + var i, j, shrine, + index = -1, + shrineList = []; + + // Initiate shrine states + if (!this.shrineStates) { + this.shrineStates = []; + + for (i = 0; i < Config.ScanShrines.length; i += 1) { + switch (Config.ScanShrines[i]) { + case Shrines.null: // None + case Shrines.refilling: // Refilling + case Shrines.health: // Health + case Shrines.mana: // Mana + case Shrines.health_exchange: // Health Exchange (doesn't exist) + case Shrines.mana_exchange: // Mana Exchange (doesn't exist) + case Shrines.enirhs: // Enirhs (doesn't exist) + case Shrines.portal: // Portal + case Shrines.gem: // Gem + case Shrines.fire: // Fire + case Shrines.monster: // Monster + case Shrines.exploding: // Exploding + case Shrines.poison: // Poison + this.shrineStates[i] = 0; // no state + + break; + case Shrines.armor: // Armor + case Shrines.combat: // Combat + case Shrines.resist_fire: // Resist Fire + case Shrines.resist_cold: // Resist Cold + case Shrines.resist_lightning: // Resist Lightning + case Shrines.resist_poison: // Resist Poison + case Shrines.skill: // Skill + case Shrines.mana_recharge: // Mana recharge + case Shrines.stamina: // Stamina + case Shrines.experience: // Experience + // Both states and shrines are arranged in same order with armor shrine starting at 128 + this.shrineStates[i] = Config.ScanShrines[i] + 122; + + break; + } + } + } + + shrine = getUnit(UnitType.Object, "shrine"); + + if (shrine) { + // Build a list of nearby shrines + do { + if (shrine.mode === ObjectModes.Neutral && getDistance(me.x, me.y, shrine.x, shrine.y) <= range) { + shrineList.push(copyUnit(shrine)); + } + } while (shrine.getNext()); + + // Check if we have a shrine state, store its index if yes + for (i = 0; i < this.shrineStates.length; i += 1) { + if (me.getState(this.shrineStates[i])) { + index = i; + + break; + } + } + + for (i = 0; i < Config.ScanShrines.length; i += 1) { + for (j = 0; j < shrineList.length; j += 1) { + // 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] && (Pather.useTeleport || !checkCollision(me, shrineList[j], 0x4))) { + this.getShrine(shrineList[j]); + + // Gem shrine - pick gem + if (Config.ScanShrines[i] === Shrines.gem) { + Pickit.pickItems(); + } + } + } + } + } + } + return true; }, // Use a shrine Unit getShrine: function (unit) { + if (unit.mode) { + return false; + } + var i, tick; for (i = 0; i < 3; i += 1) { - if (getDistance(me, unit) < 4 || Pather.moveToUnit(unit, 2, 0)) { - unit.interact(); + if (getDistance(me, unit) < 4 || Pather.moveToUnit(unit, 3, 0)) { + Misc.click(0, 0, unit); + //unit.interact(); } tick = getTickCount(); @@ -283,7 +1108,7 @@ var Misc = { }, // Check all shrines in area and get the first one of specified type - getShrinesInArea: function (area, type) { + getShrinesInArea: function (area, type, use) { var i, coords, shrine, shrineLocs = [], shrineIds = [2, 81, 83], @@ -302,16 +1127,18 @@ var Misc = { coords = shrineLocs.shift(); - Pather.moveTo(coords[0], coords[1], 2, false, true); + Pather.moveTo(coords[0], coords[1], 2); - shrine = getUnit(2, "shrine"); + shrine = getUnit(UnitType.Object, "shrine"); if (shrine) { do { - if (shrine.objtype === type) { - this.getShrine(shrine); + if (shrine.objtype === type && shrine.mode === ObjectModes.Neutral) { + Pather.moveTo(shrine.x - 2, shrine.y - 2); - return true; + if (!use || this.getShrine(shrine)) { + return true; + } } } while (shrine.getNext()); } @@ -320,80 +1147,378 @@ var Misc = { return false; }, - // Log kept item stats in the manager. It's buggy. - logItem: function (action, unit) { // hackit to the max - var val, - name = unit.fname.split("\n").reverse().join(" ").replace(/ÿc[0-9!"+<;.*]/, ""), - desc = ""; + getItemDesc: function (unit) { + var i, desc, + stringColor = ""; + + 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) { + if (desc[i].indexOf(getLocaleString(3331)) > -1) { // Remove sell value + desc.splice(i, 1); + + i -= 1; + } else { + if (desc[i].match(/^(y|ÿ)c/)) { + stringColor = desc[i].substring(0, 3); + } else { + desc[i] = stringColor + desc[i]; + } + } - desc += (Pickit.itemColor(unit) + unit.fname.split("\n").reverse().join("\n").replace(/ÿc[0-9!"+<;.*]/, "") + "ÿc0"); - val = unit.getStat(31); + desc[i] = desc[i].replace(/(y|ÿ)c([0-9!"+<;.*])/g, "\\xffc$2"); + } - if (val) { - desc += ("\nDefense: " + val); + if (desc[desc.length - 1]) { + desc[desc.length - 1] = desc[desc.length - 1].trim() + " (" + unit.ilvl + ")"; } - if (unit.getStat(21)) { - desc += ("\nOne-Hand Damage: " + unit.getStat(21) + " to " + unit.getStat(22)); + desc = desc.reverse().join("\n"); + + return desc; + }, + + getItemSockets: function (unit) { + var i, code, + sockets = unit.getStat(Stats.item_numsockets), + subItems = unit.getItems(), + tempArray = []; + + if (subItems) { + switch (unit.sizex) { + case 2: + switch (unit.sizey) { + case 3: // 2 x 3 + switch (sockets) { + case 4: + tempArray = [subItems[0], subItems[3], subItems[2], subItems[1]]; + + break; + case 5: + tempArray = [subItems[1], subItems[4], subItems[0], subItems[3], subItems[2]]; + + break; + case 6: + tempArray = [subItems[0], subItems[3], subItems[1], subItems[4], subItems[2], subItems[5]]; + + break; + } + + break; + case 4: // 2 x 4 + switch (sockets) { + case 5: + tempArray = [subItems[1], subItems[4], subItems[0], subItems[3], subItems[2]]; + + break; + case 6: + tempArray = [subItems[0], subItems[3], subItems[1], subItems[4], subItems[2], subItems[5]]; + + break; + } + + break; + } + + break; + } + + if (tempArray.length === 0 && subItems.length > 0) { + tempArray = subItems.slice(0); + } } - if (unit.getStat(23)) { - desc += ("\nTwo-Hand Damage: " + unit.getStat(23) + " to " + unit.getStat(24)); + for (i = 0; i < sockets; i += 1) { + if (tempArray[i]) { + code = tempArray[i].code; + + if ([NTItemTypes.ring, NTItemTypes.amulet, NTItemTypes.jewel, NTItemTypes.smallcharm, NTItemTypes.mediumcharm, NTItemTypes.largecharm].indexOf(tempArray[i].itemType) > -1) { + code += (tempArray[i].gfx + 1); + } + } else { + code = "gemsocket"; + } + + tempArray[i] = code; } - val = getBaseStat("items", unit.classid, 52); + return tempArray; + }, + + useItemLog: true, // Might be a bit dirty - if (val) { - desc += ("\nRequired Strength: " + val); + itemLogger: function (action, unit, text) { + if (!Config.ItemInfo || !this.useItemLog) { + return false; } - val = getBaseStat("items", unit.classid, 53); + var desc, + date = new Date(), + 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) + "]"; + + switch (action) { + case "Sold": + if (Config.ItemInfoQuality.indexOf(unit.quality) === -1) { + return false; + } + + desc = this.getItemDesc(unit).split("\n").join(" | ").replace(/(\\xff|ÿ)c[0-9!"+<;.*]/gi, "").trim(); + + break; + case "Kept": + case "Field Kept": + case "Runeword Kept": + case "Cubing Kept": + case "Shopped": + case "Gambled": + case "Dropped": + desc = this.getItemDesc(unit).split("\n").join(" | ").replace(/(\\xff|ÿ)c[0-9!"+<;.*]/gi, "").trim(); + + break; + case "No room for": + desc = unit.name; + + break; + default: + desc = unit.fname.split("\n").reverse().join(" ").replace(/(\\xff|ÿ)c[0-9!"+<;.*]/gi, "").trim(); - if (val) { - desc += ("\nRequired Dexterity: " + val); + break; } - val = unit.getStat(92); + return this.fileAction("logs/ItemLog.txt", 2, dateString + " <" + me.profile + "> <" + action + "> (" + Pickit.itemQualityToName(unit.quality) + ") " + desc + (text ? " {" + text + "}" : "") + "\n"); + }, - if (val) { - desc += ("\nRequired Level: " + val); + // Log kept item stats in the manager. + logItem: function (action, unit, keptLine) { + if (!this.useItemLog) { + return false; } - desc += ("ÿc3" + unit.description.split("\n").reverse().join("\n") + "ÿc0"); - val = unit.getStat(194); + var i, lastArea, code, desc, sock, itemObj, + color = -1, + name = unit.fname.split("\n").reverse().join(" ").replace(/ÿc[0-9!"+<;.*]/, "").trim(); - if (val) { - desc += ("\nSockets: " + val); + desc = this.getItemDesc(unit); + color = unit.getColor(); + + if (action.match("kept", "i")) { + lastArea = DataFile.getStats().lastArea; + + if (lastArea) { + desc += ("\n\\xffc0Area: " + lastArea); + } } - if (!unit.getFlag(0x10)) { - desc += "\nÿc1Unidentifiedÿc0"; + if (unit.getFlag(ItemFlags.isIdentified)) { + switch (unit.quality) { + case ItemQuality.Set: // Set + switch (unit.classid) { + case ItemClassIds.Sabre: // Angelic sabre + code = "inv9sbu"; + + break; + case ItemClassIds.Short_War_Bow: // Arctic short war bow + code = "invswbu"; + + break; + case ItemClassIds.Helm: // Berserker's helm + code = "invhlmu"; + + break; + case ItemClassIds.Large_Shield: // Civerb's large shield + code = "invlrgu"; + + break; + case ItemClassIds.Long_Sword: // Cleglaw's long sword + case ItemClassIds.Cryptic_Sword: // Szabi's cryptic sword + code = "invlsdu"; + + break; + case ItemClassIds.Small_Shield: // Cleglaw's small shield + code = "invsmlu"; + + break; + case ItemClassIds.Buckler: // Hsaru's buckler + code = "invbucu"; + + break; + case ItemClassIds.Cap: // Infernal cap / Sander's cap + code = "invcapu"; + + break; + case ItemClassIds.Broad_Sword: // Isenhart's broad sword + code = "invbsdu"; + + break; + case ItemClassIds.Full_Helm: // Isenhart's full helm + code = "invfhlu"; + + break; + case ItemClassIds.Gothic_Shield: // Isenhart's gothic shield + code = "invgtsu"; + + break; + case ItemClassIds.Ancient_Armor: // Milabrega's ancient armor + case ItemClassIds.Sacred_Armor: // Immortal King's sacred armor + code = "invaaru"; + + break; + case ItemClassIds.Kite_Shield: // Milabrega's kite shield + code = "invkitu"; + + break; + case ItemClassIds.Tower_Shield: // Sigon's tower shield + code = "invtowu"; + + break; + case ItemClassIds.Full_Plate_Mail: // Tancred's full plate mail + code = "invfulu"; + + break; + case ItemClassIds.Military_Pick: // Tancred's military pick + code = "invmpiu"; + + break; + case ItemClassIds.Jagged_Star: // Aldur's jagged star + code = "invmstu"; + + break; + case ItemClassIds.Colossus_Blade: // Bul-Kathos' colossus blade + code = "invgsdu"; + + break; + case ItemClassIds.Ornate_Plate: // Grizwold's ornate plate + code = "invxaru"; + + break; + case ItemClassIds.Cuirass: // Heaven's cuirass + case ItemClassIds.Reinforced_Mace: // Heaven's reinforced mace + case ItemClassIds.Ward: // Heaven's ward + case ItemClassIds.Spired_Helm: // Heaven's spired helm + code = "inv" + unit.code + "s"; + + break; + case ItemClassIds.Grand_Crown: // Hwanin's grand crown + code = "invxrnu"; + + break; + case ItemClassIds.Scissors_Suwayyah: // Nalya's scissors suwayyah + code = "invskru"; + + break; + case ItemClassIds.Grim_Helm: // Nalya's grim helm + case ItemClassIds.Bone_Visage: // Trang-Oul's bone visage + code = "invbhmu"; + + break; + case ItemClassIds.Elder_Staff: // Naj's elder staff + code = "invcstu"; + + break; + case ItemClassIds.Round_Shield: // Orphan's round shield + code = "invxmlu"; + + break; + case ItemClassIds.Bone_Wand: // Sander's bone wand + code = "invbwnu"; + + break; + } + + break; + case ItemQuality.Unique: // Unique + for (i = 0; i < 401; i += 1) { + if (unit.fname.split("\n").reverse()[0].indexOf(getLocaleString(getBaseStat(BaseStat.uniqueitems, i, 2))) > -1) { + code = getBaseStat(BaseStat.uniqueitems, i, "invfile"); + + break; + } + } + + break; + } } - if (unit.getFlag(0x400000)) { - desc += "\nÿc3Etherealÿc0"; + if (!code) { + if (["ci2", "ci3"].indexOf(unit.code) > -1) { // Tiara/Diadem + code = unit.code; + } else { + code = getBaseStat(BaseStat.items, unit.classid, 'normcode') || unit.code; + } + + code = code.replace(" ", ""); + + if ([NTItemTypes.ring, NTItemTypes.amulet, NTItemTypes.jewel, NTItemTypes.smallcharm, NTItemTypes.mediumcharm, NTItemTypes.largecharm].indexOf(unit.itemType) > -1) { + code += (unit.gfx + 1); + } } - desc += ("\nItem Level: " + unit.ilvl); + sock = unit.getItem(); - val = DataFile.getStats().lastArea; + if (sock) { + do { + if (sock.itemType === NTItemTypes.jewel) { + desc += "\n\n"; + desc += this.getItemDesc(sock); + } + } while (sock.getNext()); + } - if (val) { - desc += ("\nArea: " + val); + if (keptLine) { + desc += ("\n\\xffc0Line: " + keptLine); } - D2Bot.printToItemLog(action + " " + name + "$" + desc); + itemObj = { + title: action + " " + name, + description: desc, + image: code, + textColor: unit.quality, + itemColor: color, + header: "", + sockets: this.getItemSockets(unit) + }; + + D2Bot.printToItemLog(itemObj); + + return true; }, // Change into werewolf or werebear - shapeShift: function (mode) { // 0 = werewolf, 1 = werebear - if (arguments.length === 0 || mode < 0 || mode > 2) { - throw new Error("Misc.shapeShift: Invalid parameter"); + shapeShift: function (mode) { + var i, tick, skill, state; + + switch (mode.toString().toLowerCase()) { + case "0": + return false; + case "1": + case "werewolf": + state = States.WOLF; + skill = Skills.Druid.Wearwolf; + + break; + case "2": + case "werebear": + state = States.BEAR; + skill = Skills.Druid.Wearbear; + + break; + default: + throw new Error("shapeShift: Invalid parameter"); } - var i, tick, - state = mode === 0 ? 139 : 140, - skill = mode === 0 ? 223 : 228; + if (me.getState(state)) { + return true; + } for (i = 0; i < 3; i += 1) { Skill.cast(skill, 0); @@ -402,6 +1527,8 @@ var Misc = { while (getTickCount() - tick < 2000) { if (me.getState(state)) { + delay(250); + return true; } @@ -416,14 +1543,16 @@ var Misc = { unShift: function () { var i, tick; - if (me.getState(139) || me.getState(140)) { + if (me.getState(States.WOLF) || me.getState(States.BEAR)) { for (i = 0; i < 3; i += 1) { - Skill.cast(me.getState(139) ? 223 : 228); + Skill.cast(me.getState(States.WOLF) ? Skills.Druid.Wearwolf : Skills.Druid.Wearbear); tick = getTickCount(); while (getTickCount() - tick < 2000) { - if (!me.getState(139) && !me.getState(140)) { + if (!me.getState(States.WOLF) && !me.getState(States.BEAR)) { + delay(250); + return true; } @@ -447,142 +1576,843 @@ var Misc = { }, // Go to town when low on hp/mp or when out of potions. can be upgraded to check for curses etc. - townCheck: function (tpchicken) { - var potion, check, + townCheck: function () { + var i, potion, check, needhp = true, needmp = true; - if (tpchicken && ((Config.TownHP > 0 && me.hp < Math.floor(me.hpmax * Config.TownHP / 100)) || (Config.TownMP > 0 && me.hp < Math.floor(me.hpmax * Config.TownMP / 100)))) { - check = true; + // Can't tp from uber trist or when dead + if (me.area === Areas.UberLevels.Tristram || me.dead) { + return false; } if (Config.TownCheck && !me.inTown) { - if (Config.BeltColumn.indexOf("hp") > -1) { - potion = me.getItem(-1, 2); // belt item - - if (potion) { - do { - if (potion.code.indexOf("hp") > -1) { - needhp = false; - - break; + try { + if (me.gold > 1000) { + for (i = 0; i < 4; i += 1) { + if (Config.BeltColumn[i] === "hp" && Config.MinColumn[i] > 0) { + potion = me.getItem(-1, ItemLocation.Belt); // belt item + + if (potion) { + do { + if (potion.code.indexOf("hp") > -1) { + needhp = false; + + break; + } + } while (potion.getNext()); + } + + if (needhp) { + print("We need healing potions"); + + check = true; + } } - } while (potion.getNext()); - } - if (needhp) { - print("We need healing potions"); + if (Config.BeltColumn[i] === "mp" && Config.MinColumn[i] > 0) { + potion = me.getItem(-1, ItemLocation.Belt); // belt item - check = true; - } - } + if (potion) { + do { + if (potion.code.indexOf("mp") > -1) { + needmp = false; - if (Config.BeltColumn.indexOf("mp") > -1) { - potion = me.getItem(-1, 2); // belt item + break; + } + } while (potion.getNext()); + } - if (potion) { - do { - if (potion.code.indexOf("mp") > -1) { - needmp = false; + if (needmp) { + print("We need mana potions"); - break; + check = true; + } } - } while (potion.getNext()); + } } - if (needmp) { - print("We need mana potions"); - + if (Config.OpenChests && Town.needKeys()) { check = true; } + } catch (e) { + check = false; } } if (check) { - Town.goToTown(); - Town.heal(); - Town.buyPotions(); - Town.reviveMerc(); - me.cancel(); - Town.move("portalspot"); - - if (!Pather.usePortal(null, me.name)) { - throw new Error("Misc.townCheck: Failed to use portal."); - } - - if (Config.PublicMode) { - Pather.makePortal(); - } + scriptBroadcast("townCheck"); + delay(500); return true; } return false; - } -}; - -var Sort = { - // Sort units by comparing distance between the player - units: function (a, b) { - return getDistance(me, a) - getDistance(me, b); }, - // Sort preset units by comparing distance between the player (using preset x/y calculations) - presetUnits: function (a, b) { - return getDistance(me, a.roomx * 5 + a.x, a.roomy * 5 + a.y) - getDistance(me, b.roomx * 5 + b.x, b.roomy * 5 + b.y); - }, + // Log someone's gear + spy: function (name) { + if (!isIncluded("oog.js")) { + include("oog.js"); + } - // Sort arrays of x,y coords by comparing distance between the player - points: function (a, b) { - return getDistance(me, a[0], a[1]) - getDistance(me, b[0], b[1]); - } -}; + if (!isIncluded("common/prototypes.js")) { + include("common/prototypes.js"); + } -var Experience = { - totalExp: [0, 0, 500, 1500, 3750, 7875, 14175, 22680, 32886, 44396, 57715, 72144, 90180, 112725, 140906, 176132, 220165, 275207, 344008, 430010, 537513, 671891, 839864, 1049830, 1312287, 1640359, 2050449, 2563061, 3203826, 3902260, 4663553, 5493363, 6397855, 7383752, 8458379, 9629723, 10906488, 12298162, 13815086, 15468534, 17270791, 19235252, 21376515, 23710491, 26254525, 29027522, 32050088, 35344686, 38935798, 42850109, 47116709, 51767302, 56836449, 62361819, 68384473, 74949165, 82104680, 89904191, 98405658, 107672256, 117772849, 128782495, 140783010, 153863570, 168121381, 183662396, 200602101, 219066380, 239192444, 261129853, 285041630, 311105466, 339515048, 370481492, 404234916, 441026148, 481128591, 524840254, 572485967, 624419793, 681027665, 742730244, 809986056, 883294891, 963201521, 1050299747, 1145236814, 1248718217, 1361512946, 1484459201, 1618470619, 1764543065, 1923762030, 2097310703, 2286478756, 2492671933, 2717422497, 2962400612, 3229426756, 3520485254, 0, 0], - nextExp: [0, 500, 1000, 2250, 4125, 6300, 8505, 10206, 11510, 13319, 14429, 18036, 22545, 28181, 35226, 44033, 55042, 68801, 86002, 107503, 134378, 167973, 209966, 262457, 328072, 410090, 512612, 640765, 698434, 761293, 829810, 904492, 985897, 1074627, 1171344, 1276765, 1391674, 1516924, 1653448, 1802257, 1964461, 2141263, 2333976, 2544034, 2772997, 3022566, 3294598, 3591112, 3914311, 4266600, 4650593, 5069147, 5525370, 6022654, 6564692, 7155515, 7799511, 8501467, 9266598, 10100593, 11009646, 12000515, 13080560, 14257811, 15541015, 16939705, 18464279, 20126064, 21937409, 23911777, 26063836, 28409582, 30966444, 33753424, 36791232, 40102443, 43711663, 47645713, 51933826, 56607872, 61702579, 67255812, 73308835, 79906630, 87098226, 94937067, 103481403, 112794729, 122946255, 134011418, 146072446, 159218965, 173548673, 189168053, 206193177, 224750564, 244978115, 267026144, 291058498, 0, 0], + var item, + unit = getUnit(-1, name); - // Percent progress into the current level. Format: xx.xx% - progress: function () { - return me.getStat(12) === 99 ? 0 : (((me.getStat(13) - this.totalExp[me.getStat(12)]) / this.nextExp[me.getStat(12)]) * 100).toFixed(2); - }, + if (!unit) { + print("player not found"); - // Total experience gained in current run - gain: function () { - return (me.getStat(13) - DataFile.getStats().experience); - }, + return false; + } - // Percent experience gained in current run - gainPercent: function () { - return me.getStat(12) === 99 ? 0 : (this.gain() * 100 / this.nextExp[me.getStat(12)]).toFixed(6); - }, + item = unit.getItem(); - // Runs until next level - runsToLevel: function () { - return Math.round(((100 - this.progress()) / 100) * this.nextExp[me.getStat(12)] / this.gain()); - }, + if (item) { + do { + this.logItem(unit.name, item); + } while (item.getNext()); + } - // Total runs needed for next level (not counting current progress) - totalRunsToLevel: function () { - return Math.round(this.nextExp[me.getStat(12)] / this.gain()); + return true; }, - // Log to manager - log: function () { - var string, - gain = this.gain(), - progress = this.progress(), - runsToLevel = this.runsToLevel(), - totalRunsToLevel = this.totalRunsToLevel(); + // hopefully multi-thread and multi-profile friendly txt func + /*fileAction: function (path, mode, msg) { + var i, file, + contents = ""; - string = "XP Gain: " + gain + ", Progress: " + me.getStat(12) + " (" + progress + "%), Est. runs until level-up: " + runsToLevel + "/" + totalRunsToLevel; +MainLoop: + for (i = 0; i < 30; i += 1) { + try { + file = File.open(path, mode); - if (gain) { - D2Bot.printToConsole(string + ";2"); + switch (mode) { + case 0: // read + contents = file.readLine(); + + break MainLoop; + case 1: // write + case 2: // append + file.write(msg); - if (me.getStat(12) > DataFile.getStats().level) { - D2Bot.printToConsole("Congrats! You gained a level. Current level:" + me.getStat(12) + ";3"); + break MainLoop; + } + } catch (e) { + + } finally { + if (file) { + file.close(); + } } + + delay(100); } + + return mode === 0 ? contents : true; + },*/ + + fileAction: function (path, mode, msg) { + var i, + contents = ""; + +MainLoop: + for (i = 0; i < 30; i += 1) { + try { + switch (mode) { + case 0: // read + contents = FileTools.readText(path); + + break MainLoop; + case 1: // write + FileTools.writeText(path, msg); + + break MainLoop; + case 2: // append + FileTools.appendText(path, msg); + + break MainLoop; + } + } catch (e) { + + } + + delay(100); + } + + return mode === 0 ? contents : true; + }, + + errorConsolePrint: true, + screenshotErrors: false, + + // Report script errors to logs/ScriptErrorLog.txt + errorReport: function (error, script) { + var i, h, m, s, date, msg, oogmsg, filemsg, source, stack, + stackLog = ""; + + date = new Date(); + h = date.getHours(); + m = date.getMinutes(); + s = date.getSeconds(); + + if (typeof error === "string") { + msg = error; + oogmsg = error.replace(/ÿc[0-9!"+<;.*]/gi, ""); + filemsg = "[" + (h < 10 ? "0" + h : h) + ":" + (m < 10 ? "0" + m : m) + ":" + (s < 10 ? "0" + s : s) + "] <" + me.profile + "> " + error.replace(/ÿc[0-9!"+<;.*]/gi, "") + "\n"; + } else { + source = error.fileName.substring(error.fileName.lastIndexOf("\\") + 1, error.fileName.length); + 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) { + D2Bot.printToConsole(oogmsg, 10); + } + + showConsole(); + print(msg); + this.fileAction("logs/ScriptErrorLog.txt", 2, filemsg); + + if (this.screenshotErrors) { + takeScreenshot(); + delay(500); + } + }, + + debugLog: function (msg) { + if (!Config.Debug) { + return; + } + + debugLog(me.profile + ": " + msg); + }, + + // Use a NPC menu. Experimental function, subject to change + // id = string number (with exception of Ressurect merc). http://www.blizzhackers.cc/viewtopic.php?f=209&t=378493 + useMenu: function (id) { + //print("useMenu " + getLocaleString(id)); + + var i, npc, lines; + + switch (id) { + case 0x1507: // Resurrect (non-English dialog) + case 0x0D44: // Trade (crash dialog) + npc = getInteractedNPC(); + + if (npc) { + npc.useMenu(id); + delay(750); + + return true; + } + + break; + } + + lines = getDialogLines(); + + if (!lines) { + return false; + } + + for (i = 0; i < lines.length; i += 1) { + if (lines[i].selectable && lines[i].text.indexOf(getLocaleString(id)) > -1) { + getDialogLines()[i].handler(); + delay(750); + + return true; + } + } + + return false; + }, + + clone: function (obj) { + var i, copy, attr; + + // Handle the 3 simple types, and null or undefined + if (null === obj || "object" !== typeof obj) { + return obj; + } + + // Handle Date + if (obj instanceof Date) { + copy = new Date(); + + copy.setTime(obj.getTime()); + + return copy; + } + + // Handle Array + if (obj instanceof Array) { + copy = []; + + for (i = 0; i < obj.length; i += 1) { + copy[i] = this.clone(obj[i]); + } + + return copy; + } + + // Handle Object + if (obj instanceof Object) { + copy = {}; + + for (attr in obj) { + if (obj.hasOwnProperty(attr)) { + copy[attr] = this.clone(obj[attr]); + } + } + + return copy; + } + + throw new Error("Unable to copy obj! Its type isn't supported."); + }, + + copy: function (from) { + var i, + obj = {}; + + for (i in from) { + if (from.hasOwnProperty(i)) { + obj[i] = this.clone(from[i]); + } + } + + return obj; + } +}; + +var Sort = { + // Sort units by comparing distance between the player + units: function (a, b) { + return Math.round(getDistance(me.x, me.y, a.x, a.y)) - Math.round(getDistance(me.x, me.y, b.x, b.y)); + }, + + // Sort preset units by comparing distance between the player (using preset x/y calculations) + presetUnits: function (a, b) { + return getDistance(me, a.roomx * 5 + a.x, a.roomy * 5 + a.y) - getDistance(me, b.roomx * 5 + b.x, b.roomy * 5 + b.y); + }, + + // Sort arrays of x,y coords by comparing distance between the player + points: function (a, b) { + return getDistance(me, a[0], a[1]) - getDistance(me, b[0], b[1]); + }, + + numbers: function (a, b) { + return a - b; + } +}; + +var Experience = { + totalExp: [0, 0, 500, 1500, 3750, 7875, 14175, 22680, 32886, 44396, 57715, 72144, 90180, 112725, 140906, 176132, 220165, 275207, 344008, 430010, 537513, 671891, 839864, 1049830, 1312287, 1640359, 2050449, 2563061, 3203826, 3902260, 4663553, 5493363, 6397855, 7383752, 8458379, 9629723, 10906488, 12298162, 13815086, 15468534, 17270791, 19235252, 21376515, 23710491, 26254525, 29027522, 32050088, 35344686, 38935798, 42850109, 47116709, 51767302, 56836449, 62361819, 68384473, 74949165, 82104680, 89904191, 98405658, 107672256, 117772849, 128782495, 140783010, 153863570, 168121381, 183662396, 200602101, 219066380, 239192444, 261129853, 285041630, 311105466, 339515048, 370481492, 404234916, 441026148, 481128591, 524840254, 572485967, 624419793, 681027665, 742730244, 809986056, 883294891, 963201521, 1050299747, 1145236814, 1248718217, 1361512946, 1484459201, 1618470619, 1764543065, 1923762030, 2097310703, 2286478756, 2492671933, 2717422497, 2962400612, 3229426756, 3520485254, 0, 0], + nextExp: [0, 500, 1000, 2250, 4125, 6300, 8505, 10206, 11510, 13319, 14429, 18036, 22545, 28181, 35226, 44033, 55042, 68801, 86002, 107503, 134378, 167973, 209966, 262457, 328072, 410090, 512612, 640765, 698434, 761293, 829810, 904492, 985897, 1074627, 1171344, 1276765, 1391674, 1516924, 1653448, 1802257, 1964461, 2141263, 2333976, 2544034, 2772997, 3022566, 3294598, 3591112, 3914311, 4266600, 4650593, 5069147, 5525370, 6022654, 6564692, 7155515, 7799511, 8501467, 9266598, 10100593, 11009646, 12000515, 13080560, 14257811, 15541015, 16939705, 18464279, 20126064, 21937409, 23911777, 26063836, 28409582, 30966444, 33753424, 36791232, 40102443, 43711663, 47645713, 51933826, 56607872, 61702579, 67255812, 73308835, 79906630, 87098226, 94937067, 103481403, 112794729, 122946255, 134011418, 146072446, 159218965, 173548673, 189168053, 206193177, 224750564, 244978115, 267026144, 291058498, 0, 0], + + // Percent progress into the current level. Format: xx.xx% + progress: function () { + return me.getStat(Stats.level) === 99 ? 0 : (((me.getStat(Stats.experience) - this.totalExp[me.getStat(Stats.level)]) / this.nextExp[me.getStat(Stats.level)]) * 100).toFixed(2); + }, + + // Total experience gained in current run + gain: function () { + return (me.getStat(Stats.experience) - DataFile.getStats().experience); + }, + + // Percent experience gained in current run + gainPercent: function () { + return me.getStat(Stats.level) === 99 ? 0 : (this.gain() * 100 / this.nextExp[me.getStat(Stats.level)]).toFixed(6); + }, + + // Runs until next level + runsToLevel: function () { + return Math.round(((100 - this.progress()) / 100) * this.nextExp[me.getStat(Stats.level)] / this.gain()); + }, + + // Total runs needed for next level (not counting current progress) + totalRunsToLevel: function () { + return Math.round(this.nextExp[me.getStat(Stats.level)] / this.gain()); + }, + + // Total time till next level + timeToLevel: function () { + var tTLrawSeconds = (Math.floor((getTickCount() - me.gamestarttime) / 1000)).toString(), + tTLrawtimeToLevel = this.runsToLevel() * tTLrawSeconds, + tTLDays = Math.floor(tTLrawtimeToLevel / 86400), + tTLHours = Math.floor((tTLrawtimeToLevel % 86400) / 3600), + tTLMinutes = Math.floor(((tTLrawtimeToLevel % 86400) % 3600) / 60), + tTLSeconds = ((tTLrawtimeToLevel % 86400) % 3600) % 60; + + //return tDays + "d " + tTLHours + "h " + tTLMinutes + "m " + tTLSeconds + "s"; + //return tTLDays + "d " + tTLHours + "h " + tTLMinutes + "m"; + return (tTLDays ? tTLDays + " d " : "") + (tTLHours ? tTLHours + " h " : "") + (tTLMinutes ? tTLMinutes + " m" : ""); + }, + + // Get Game Time + getGameTime: function () { + var rawMinutes = Math.floor((getTickCount() - me.gamestarttime) / 60000).toString(), + rawSeconds = (Math.floor((getTickCount() - me.gamestarttime) / 1000) % 60).toString(); + + if (rawMinutes <= 9) { + rawMinutes = "0" + rawMinutes; + } + + if (rawSeconds <= 9) { + rawSeconds = "0" + rawSeconds; + } + + //return rawMinutes + "m " + rawSeconds + "s"; + return " (" + rawMinutes + ":" + rawSeconds + ")"; + }, + + // Log to manager + log: function () { + var string, + gain = this.gain(), + progress = this.progress(), + runsToLevel = this.runsToLevel(), + totalRunsToLevel = this.totalRunsToLevel(), + getGameTime = this.getGameTime(), + timeToLevel = this.timeToLevel(); + + //string = "[Game: " + me.gamename + (me.gamepassword ? "//" + me.gamepassword : "") + getGameTime + "] [Level: " + me.getStat(12) + " (" + progress + "%)] [XP: " + gain + "] [Games ETA: " + runsToLevel + "] [Time ETA: " + timeToLevel + "]"; + string = "[Game: " + me.gamename + (me.gamepassword ? "//" + me.gamepassword : "") + getGameTime + "] [Level: " + me.getStat(Stats.level) + " (" + progress + "%)] [XP: " + gain + "] [Games ETA: " + runsToLevel + "]"; + + if (gain) { + D2Bot.printToConsole(string, 4); + + if (me.getStat(Stats.level) > DataFile.getStats().level) { + D2Bot.printToConsole("Congrats! You gained a level. Current level:" + me.getStat(Stats.level), 5); + } + } + } +}; + +var Packet = { + openMenu: function (unit) { + if (unit.type !== UnitType.NPC) { + throw new Error("openMenu: Must be used on NPCs."); + } + + if (getUIFlag(UIFlags.npc_menu)) { + return true; + } + + var i, j; + + for (i = 0; i < 5; i += 1) { + if (getDistance(me, unit) > 5) { + Pather.moveToUnit(unit); + } + + if (i > 0) { + Packet.flash(me.gid); + } + + if (!getUIFlag(UIFlags.npc_menu)) { + sendPacket(1, 0x13, 4, 1, 4, unit.gid); + } + + for (j = 0; j < 40; j += 1) { + if (j > 0 && j % 8 === 0 && !getUIFlag(UIFlags.npc_menu)) { + me.cancel(); + delay(300); + sendPacket(1, 0x13, 4, 1, 4, unit.gid); + } + + if (getUIFlag(UIFlags.npc_menu)) { + delay(Math.max(500, me.ping * 2)); + + return true; + } + + delay(25); + } + } + + return false; + }, + + startTrade: function (unit, mode) { + if (unit.type !== UnitType.NPC) { + throw new Error("Unit.startTrade: Must be used on NPCs."); + } + + if (getUIFlag(UIFlags.Shop_open_at_NPC)) { + return true; + } + + var i, + gamble = mode === "Gamble"; + + if (this.openMenu(unit)) { + for (i = 0; i < 10; i += 1) { + delay(200); + + if (i % 2 === 0) { + sendPacket(1, 0x38, 4, gamble ? 2 : 1, 4, unit.gid, 4, 0); + } + + if (unit.itemcount > 0) { + delay(200); + + return true; + } + } + } + + return false; + }, + + buyItem: function (unit, shiftBuy, gamble) { + var i, tick, + oldGold = me.getStat(Stats.gold) + me.getStat(Stats.goldbank), + itemCount = me.itemcount, + npc = getInteractedNPC(); + + if (!npc) { + throw new Error("buyItem: No NPC menu open."); + } + + if (me.getStat(Stats.gold) + me.getStat(Stats.goldbank) < unit.getItemCost(0)) { // Can we afford the item? + return false; + } + + for (i = 0; i < 3; i += 1) { + sendPacket(1, 0x32, 4, npc.gid, 4, unit.gid, 4, shiftBuy ? 0x80000000 : gamble ? 0x2 : 0x0, 4, 0); + + tick = getTickCount(); + + while (getTickCount() - tick < Math.max(2000, me.ping * 2 + 500)) { + if (shiftBuy && me.getStat(Stats.gold) + me.getStat(Stats.goldbank) < oldGold) { + return true; + } + + if (itemCount !== me.itemcount) { + return true; + } + + delay(10); + } + } + + return false; + }, + + sellItem: function (unit) { + if (unit.type !== NTItemTypes.gold) { // Check if it's an item we want to buy + throw new Error("Unit.sell: Must be used on items."); + } + + var i, tick, npc, + itemCount = me.itemcount; + + npc = getInteractedNPC(); + + if (!npc) { + return false; + } + + for (i = 0; i < 5; i += 1) { + sendPacket(1, 0x33, 4, npc.gid, 4, unit.gid, 4, 0, 4, 0); + + tick = getTickCount(); + + while (getTickCount() - tick < 2000) { + if (me.itemcount !== itemCount) { + return true; + } + + delay(10); + } + } + + return false; + }, + + identifyItem: function (unit, tome) { + var i, tick; + + if (!unit || unit.getFlag(ItemFlags.isIdentified)) { + return false; + } + +CursorLoop: + for (i = 0; i < 3; i += 1) { + sendPacket(1, 0x27, 4, unit.gid, 4, tome.gid); + + tick = getTickCount(); + + while (getTickCount() - tick < 2000) { + if (getCursorType() === 6) { + break CursorLoop; + } + + delay(10); + } + } + + if (getCursorType() !== 6) { + return false; + } + + for (i = 0; i < 3; i += 1) { + if (getCursorType() === 6) { + sendPacket(1, 0x27, 4, unit.gid, 4, tome.gid); + } + + tick = getTickCount(); + + while (getTickCount() - tick < 2000) { + if (unit.getFlag(ItemFlags.isIdentified)) { + delay(50); + + return true; + } + + delay(10); + } + } + + 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); + }, + + unitCast: function (hand, who) { + hand = (hand === 0) ? 0x11 : 0x0a; + sendPacket(1, hand, 4, who.type, 4, who.gid); + }, + + moveNPC: function (npc, dwX, dwY) { + sendPacket(1, 0x59, 4, npc.type, 4, npc.gid, 4, dwX, 4, dwY); + }, + + 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) { + sendPacket(1, 0x4b, 4, 0, 4, gid); + }, + + changeStat: function (stat, value) { + if (value > 0) { + 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 f11e0e8b6..46fce423d 100644 --- a/d2bs/kolbot/libs/common/Pather.js +++ b/d2bs/kolbot/libs/common/Pather.js @@ -4,64 +4,186 @@ * @desc handle player movement */ +// Perform certain actions after moving to each node +var NodeAction = { + // Run all the functions within NodeAction (except for itself) + go: function (arg) { + var i; + + for (i in this) { + if (this.hasOwnProperty(i) && typeof this[i] === "function" && i !== "go") { + this[i](arg); + } + } + }, + + // Kill monsters while pathing + killMonsters: function (arg) { + var monList; + + if (Config.Countess.KillGhosts && [Areas.Act1.Tower_Cellar_Level_1, Areas.Act1.Tower_Cellar_Level_2, Areas.Act1.Tower_Cellar_Level_3, Areas.Act1.Tower_Cellar_Level_4, Areas.Act1.Tower_Cellar_Level_5].indexOf(me.area) > -1) { + monList = Attack.getMob(MonsterClassID.wraith1.hcIdx, 0, 30); + + if (monList) { + Attack.clearList(monList); + } + } + + if ((typeof Config.ClearPath === "number" || typeof Config.ClearPath === "object") && arg.clearPath === false) { + switch (typeof Config.ClearPath) { + case "number": + Attack.clear(30, Config.ClearPath); + + break; + case "object": + 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 (arg.clearPath !== false) { + Attack.clear(15, typeof arg.clearPath === "number" ? arg.clearPath : 0); + } + }, + + // Open chests while pathing + popChests: function () { + if (!!Config.OpenChests) { + Misc.openChests(20); + } + }, + + // Scan shrines while pathing + getShrines: function () { + 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: 15, + walkDistance: 10, teleDistance: 40, - 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], + cancelFlags: [0x01, 0x02, 0x04, 0x08, 0x14, 0x16, 0x0c, 0x0f, 0x17, 0x19, 0x1A], + wpAreas: [Areas.Act1.Rogue_Encampment, Areas.Act1.Cold_Plains, Areas.Act1.Stony_Field, Areas.Act1.Dark_Wood, Areas.Act1.Black_Marsh, Areas.Act1.Outer_Cloister, Areas.Act1.Jail_Level_1, Areas.Act1.Inner_Cloister, Areas.Act1.Catacombs_Level_2, + Areas.Act2.Lut_Gholein, Areas.Act2.A2_Sewers_Level_2, Areas.Act2.Dry_Hills, Areas.Act2.Halls_Of_The_Dead_Level_2, Areas.Act2.Far_Oasis, Areas.Act2.Lost_City, Areas.Act2.Palace_Cellar_Level_1, Areas.Act2.Arcane_Sanctuary, Areas.Act2.Canyon_Of_The_Magi, + Areas.Act3.Kurast_Docktown, Areas.Act3.Spider_Forest, Areas.Act3.Great_Marsh, Areas.Act3.Flayer_Jungle, Areas.Act3.Lower_Kurast, Areas.Act3.Kurast_Bazaar, Areas.Act3.Upper_Kurast, Areas.Act3.Travincal, Areas.Act3.Durance_Of_Hate_Level_2, + Areas.Act4.The_Pandemonium_Fortress, Areas.Act4.City_Of_The_Damned, Areas.Act4.River_Of_Flame, + Areas.Act5.Harrogath, Areas.Act5.Frigid_Highlands, Areas.Act5.Arreat_Plateau, Areas.Act5.Crystalized_Passage, Areas.Act5.Glacial_Trail, Areas.Act5.Halls_Of_Pain, Areas.Act5.Frozen_Tundra, Areas.Act5.Ancients_Way, Areas.Act5.The_Worldstone_Keep_Level_2], + 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) { + if (me.dead) { // Abort if dead + return false; + } + + var i, path, adjustedNode, cleared, + node = {x: x, y: y}, + fail = 0; + + for (i = 0; i < this.cancelFlags.length; i += 1) { + if (getUIFlag(this.cancelFlags[i])) { + me.cancel(); + } + } + if (getDistance(me, x, y) < 2) { return true; } - if (arguments.length < 2) { + if (x === undefined || y === undefined) { throw new Error("moveTo: Function must be called with at least 2 arguments."); } - if (typeof (x) !== "number" || typeof (y) !== "number") { + if (typeof x !== "number" || typeof y !== "number") { throw new Error("moveTo: Coords must be numbers"); } - if (getUIFlag(0x01) || getUIFlag(0x02) || getUIFlag(0x04) || getUIFlag(0x16) || getUIFlag(0x0C) || getUIFlag(0x0F)) { - me.cancel(); - } - - switch (arguments.length) { - case 2: + if (retry === undefined) { retry = 3; - clearPath = false; - pop = false; + } - break; - case 3: + if (clearPath === undefined) { clearPath = false; - pop = false; + } - break; - case 4: + if (pop === undefined) { pop = false; - - break; } - var path, mob, - node = {x: x, y: y}, - fail = 0; - - this.useTeleport = this.teleport && !me.inTown && me.getSkill(54, 1); + this.useTeleport = this.teleport && !me.getState(States.WOLF) && !me.getState(States.WOLF) && !me.inTown && + ((me.classid === ClassID.Sorceress && me.getSkill(Skills.Sorceress.Teleport, 1)) || me.getStat(Stats.item_nonclassskill, Skills.Sorceress.Teleport)); // Teleport without calling getPath if the spot is close enough if (this.useTeleport && getDistance(me, x, y) <= this.teleDistance) { + //Misc.townCheck(); + return this.teleportTo(x, y); } // Walk without calling getPath if the spot is close enough - if (!this.useTeleport && getDistance(me, x, y) <= 5) { + if (!this.useTeleport && (getDistance(me, x, y) <= 5 || (getDistance(me, x, y) <= 25 && !CollMap.checkColl(me, {x: x, y: y}, 0x1)))) { return this.walkTo(x, y); } - path = getPath(me.area, x, y, me.x, me.y, this.useTeleport ? 1 : 0, this.useTeleport ? this.teleDistance : this.walkDistance); + path = getPath(me.area, x, y, me.x, me.y, this.useTeleport ? 1 : 0, this.useTeleport ? ([Areas.Act2.Maggot_Lair_Level_1, Areas.Act2.Maggot_Lair_Level_2, Areas.Act2.Maggot_Lair_Level_3].indexOf(me.area) > -1 ? 30 : this.teleDistance) : this.walkDistance); if (!path) { throw new Error("moveTo: Failed to generate path."); @@ -73,13 +195,21 @@ var Pather = { path.pop(); } + PathDebug.drawPath(path); + if (this.useTeleport && Config.TeleSwitch) { Misc.teleSwitch(); } while (path.length > 0) { - if (getUIFlag(0x01) || getUIFlag(0x02) || getUIFlag(0x04) || getUIFlag(0x16) || getUIFlag(0x0C) || getUIFlag(0x0F)) { - me.cancel(); + if (me.dead) { // Abort if dead + return false; + } + + for (i = 0; i < this.cancelFlags.length; i += 1) { + if (getUIFlag(this.cancelFlags[i])) { + me.cancel(); + } } node = path.shift(); @@ -87,81 +217,107 @@ var Pather = { /* Right now getPath's first node is our own position so it's not necessary to take it into account This will be removed if getPath changes */ - if (this.useTeleport && getDistance(me, node) < 2) { - continue; - } + if (getDistance(me, node) > 2) { + // Make life in Maggot Lair easier + if ([Areas.Act2.Maggot_Lair_Level_1, Areas.Act2.Maggot_Lair_Level_2, Areas.Act2.Maggot_Lair_Level_3].indexOf(me.area) > -1) { + adjustedNode = this.getNearestWalkable(node.x, node.y, 15, 3, 0x1 | 0x4 | 0x800 | 0x1000); + + if (adjustedNode) { + node.x = adjustedNode[0]; + node.y = adjustedNode[1]; + } + } - if (!(this.useTeleport ? this.teleportTo(node.x, node.y) : this.walkTo(node.x, node.y))) { - // Reduce node distance in new path - path = getPath(me.area, x, y, me.x, me.y, this.useTeleport ? 1 : 0, this.useTeleport ? 30 : 10); + 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; - if (!path) { - throw new Error("moveTo: Failed to generate path."); - } + NodeAction.go({clearPath: clearPath}); - path.reverse(); + if (getDistance(me, node.x, node.y) > 5) { + this.moveTo(node.x, node.y); + } - if (fail === 2 && !this.useTeleport) { - Attack.clear(5); - } + this.recursion = true; + } - fail += 1; + Misc.townCheck(); + } + } else { + if (fail > 0 && !this.useTeleport && !me.inTown) { + // Don't go berserk on longer paths + if (!cleared) { + Attack.clear(5); - //print("move retry " + fail); - } + cleared = true; + } - if (fail >= retry) { - break; - } + if (fail > 1 && me.getSkill(Skills.Barbarian.Leap_Attack, 1)) { + Skill.cast(Skills.Barbarian.Leap_Attack, 0, node.x, node.y); + } + } - if (clearPath) { - Attack.clear(15, typeof clearPath === "number" ? clearPath : false); + // Reduce node distance in new path + 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 (getDistance(me, node.x, node.y) > 4) { - this.moveTo(node.x, node.y); - } - } + if (!path) { + throw new Error("moveTo: Failed to generate path."); + } - if (Config.Countess.KillGhosts) { // TODO: expand&improve - mob = Attack.getMob("ghost", 0, 30); + path.reverse(); + PathDebug.drawPath(path); - if (mob) { - Attack.clearList(mob); - } + if (pop) { + path.pop(); + } - if (getDistance(me, node.x, node.y) > 4) { - this.moveTo(node.x, node.y); + print("move retry " + fail); + + if (fail > 0 && fail >= retry) { + break; + } } } - if (Misc.townCheck(false)) { - this.useTeleport = this.teleport && !me.inTown && me.getSkill(54, 1); - } + delay(5); } if (this.useTeleport && Config.TeleSwitch) { Precast.weaponSwitch(Misc.oldSwitch); } - return getDistance(me, node.x, node.y) < 4; + 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 (typeof castXY === "function") { - Skill.setSkill(54, 0); - castXY(0, x, y); + if (Config.PacketCasting) { + Skill.setSkill(Skills.Sorceress.Teleport, 0); + Packet.castSkill(0, x, y); } else { Skill.cast(54, 0, x, y); } tick = getTickCount(); - while (getTickCount() - tick < 500) { - if (getDistance(me, x, y) < 5) { + while (getTickCount() - tick < Math.max(500, me.ping * 2 + 200)) { + if (getDistance(me.x, me.y, x, y) < maxRange) { return true; } @@ -172,48 +328,70 @@ MainLoop: return false; }, - walkTo: function (x, y) { - var nTimer, + /* + 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); + } + + if (minDist === undefined) { + minDist = me.inTown ? 2 : 4; + } + + var i, angle, angles, nTimer, whereToClick, tick, nFail = 0, attemptCount = 0; - if (me.runwalk === 0) { - 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.mode !== 17 && !me.inTown && me.mp >= 9 && getDistance(me, 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; } - clickMap(0, 1, x, y); - delay(20); - clickMap(2, 1, x, y); + if (Config.Charge && me.classid === ClassID.Paladin && me.mp >= 9 && getDistance(me.x, me.y, x, y) > 8 && Skill.setSkill(Skills.Paladin.Charge, 1)) { + if (Config.Vigor) { + Skill.setSkill(Skills.Paladin.Vigor, 0); + } + + Misc.click(0, 1, x, y); - while (me.mode !== 1 && me.mode !== 5 && me.mode !== 17) { - delay(40); + while (me.mode !== PlayerModes.Neutral && me.mode !== PlayerModes.Town_Neutral && !me.dead) { + delay(40); + } } } -MainLoop: - while (getDistance(me, x, y) > 3 && me.mode !== 17) { - if (me.classid === 3 && Config.Vigor) { - Skill.setSkill(115, 0); + if (me.inTown && me.runwalk === 0) { + me.runwalk = 1; + } + + while (getDistance(me.x, me.y, x, y) > minDist && !me.dead) { + if (me.classid === ClassID.Paladin && Config.Vigor) { + Skill.setSkill(Skills.Paladin.Vigor, 0); } - if (this.openDoors(x, y) && getDistance(me, x, y) < 4) { + if (this.openDoors(x, y) && getDistance(me.x, me.y, x, y) <= minDist) { return true; } - me.move(x, y); + Misc.click(0, 0, x, y); attemptCount += 1; nTimer = getTickCount(); - while (me.mode !== 2 && me.mode !== 3 && me.mode !== 6) { - if (me.mode === 17) { - break MainLoop; +ModeLoop: + while (me.mode !== PlayerModes.Walk && me.mode !== PlayerModes.Run && me.mode !== PlayerModes.Town_Walk) { + if (me.dead) { + return false; } if ((getTickCount() - nTimer) > 500) { @@ -223,17 +401,38 @@ MainLoop: return false; } - this.walkTo(me.x + rand(-1, 1) * 4, me.y + rand(-1, 1)); // recursion motherfuckers + angle = Math.atan2(me.y - y, me.x - x); + 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); + + tick = getTickCount(); + + while (getDistance(me, whereToClick) > 2 && getTickCount() - tick < 1000) { + delay(40); + } + + break; + } + } - continue MainLoop; + break ModeLoop; } - delay(40); + delay(10); } // Wait until we're done walking - idle or dead - while (me.mode !== 1 && me.mode !== 5 && me.mode !== 17) { - delay(40); + while (getDistance(me.x, me.y, x, y) > minDist && me.mode !== PlayerModes.Neutral && me.mode !== PlayerModes.Town_Neutral && !me.dead) { + delay(10); } if (attemptCount >= 3) { @@ -241,24 +440,34 @@ MainLoop: } } - return true; + 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; + } + // Regular doors var i, tick, - door = getUnit(2, "door", 0); + door = getUnit(UnitType.Object, "door", ObjectModes.Neutral); if (door) { do { - if (getDistance(door, x, y) < 4 && getDistance(me, door) < 9 || getDistance(me, door) < 4) { // TODO: Adjust to optimal distances + if ((getDistance(door, x, y) < 4 && getDistance(me, door) < 9) || getDistance(me, door) < 4) { for (i = 0; i < 3; i += 1) { - door.interact(); + Misc.click(0, 0, door); + //door.interact(); tick = getTickCount(); while (getTickCount() - tick < 1000) { - if (door.mode === 2) { + if (door.mode === ObjectModes.Opened) { me.overhead("Opened a door!"); return true; @@ -271,39 +480,37 @@ MainLoop: } 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 - switch (arguments.length) { - case 1: + moveToUnit: function (unit, offX, offY, clearPath, pop) { + this.useTeleport = this.teleport && !me.getState(States.WOLF) && !me.getState(States.BEAR) && !me.inTown && + ((me.classid === ClassID.Sorceress && me.getSkill(Skills.Sorceress.Teleport, 1)) || me.getStat(Stats.item_nonclassskill, Skills.Sorceress.Teleport)); + + if (offX === undefined) { offX = 0; - offY = 0; - clearPath = false; - pop = false; + } - break; - case 2: + if (offY === undefined) { offY = 0; - clearPath = false; - pop = false; + } - break; - case 3: + if (clearPath === undefined) { clearPath = false; - pop = false; + } - break; - case 4: + if (pop === undefined) { pop = false; - - break; } if (!unit || !unit.hasOwnProperty("x") || !unit.hasOwnProperty("y")) { @@ -314,40 +521,43 @@ MainLoop: return this.moveTo(unit.roomx * 5 + unit.x + offX, unit.roomy * 5 + unit.y + offY, 3, clearPath); } - return this.moveTo(unit.x + offX, unit.y + offY, 3, clearPath, pop); + if (!this.useTeleport) { + // The unit will most likely be moving so call the first walk with 'pop' parameter + this.moveTo(unit.x + offX, unit.y + offY, 0, clearPath, true); + } + + return this.moveTo(unit.x + offX, unit.y + offY, this.useTeleport && unit.type && unit.type === UnitType.NPC ? 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 (arguments.length < 3) { + if (area === undefined || unitType === undefined || unitId === undefined) { throw new Error("moveToPreset: Invalid parameters."); } - switch (arguments.length) { - case 3: + if (offX === undefined) { offX = 0; - offY = 0; - clearPath = false; - pop = false; + } - break; - case 4: + if (offY === undefined) { offY = 0; - clearPath = false; - pop = false; + } - break; - case 5: + if (clearPath === undefined) { clearPath = false; - pop = false; + } - break; - case 6: + if (pop === undefined) { pop = false; - - break; } var presetUnit = getPresetUnit(area, unitType, unitId); @@ -359,10 +569,14 @@ MainLoop: 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, n, exits, targetExits, - dest = {}, + var i, j, area, exits, targetRoom, dest, currExit, areas = []; if (targetArea instanceof Array) { @@ -372,49 +586,56 @@ MainLoop: } for (i = 0; i < areas.length; i += 1) { - exits = getArea().exits; + area = getArea(); + + if (!area) { + throw new Error("moveToExit: error in getArea()"); + } + + exits = area.exits; if (!exits || !exits.length) { return false; } for (j = 0; j < exits.length; j += 1) { - if (exits[j].target === areas[i]) { - this.moveToUnit(exits[j], 0, 0, clearPath); + 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 (!this.moveTo(dest[0], dest[1], 3, clearPath)) { + return false; + } /* i < areas.length - 1 is for crossing multiple areas. In that case we must use the exit before the last area. */ if (use || i < areas.length - 1) { - switch (exits[j].type) { - case 1: - targetExits = getArea(areas[i]).exits; - - if (!targetExits || !targetExits.length) { + switch (currExit.type) { + case 1: // walk through + targetRoom = this.getNearestRoom(areas[i]); + + if (targetRoom) { + this.moveTo(targetRoom[0], targetRoom[1]); + } else { + // might need adjustments return false; } - for (n = 0; n < targetExits.length; n += 1) { - if (targetExits[n].target === me.area) { // TODO: Add getNearestRoom back in - dest.angle = Math.round(Math.atan2(exits[j].y - targetExits[n].y, exits[j].x - targetExits[n].x) * 180 / Math.PI); - dest.x = Math.round((Math.cos((dest.angle + 180) * Math.PI / 180)) * 10 + targetExits[n].x); - dest.y = Math.round((Math.sin((dest.angle + 180) * Math.PI / 180)) * 10 + targetExits[n].y); - - /*if (!this.moveToUnit(targetExits[n])) { - return false; - }*/ - - if (!this.moveTo(dest.x, dest.y, 3)) { - return false; - } - - break; - } - } - break; - case 2: - if (!this.useUnit(5, exits[j].tileid, areas[i])) { + case 2: // stairs + if (!this.useUnit(5, currExit.tileid, areas[i])) { return false; } @@ -427,36 +648,93 @@ MainLoop: } } + if (use) { + return typeof targetArea === "object" ? me.area === targetArea[targetArea.length - 1] : me.area === targetArea; + } + 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; + + for (i = 0; i < 5; i += 1) { + room = getRoom(area); + + if (room) { + break; + } + + delay(200); + } + + if (!room) { + return false; + } + + do { + dist = getDistance(me, room.x * 5 + room.xsize / 2, room.y * 5 + room.ysize / 2); + + if (dist < minDist) { + x = room.x * 5 + room.xsize / 2; + y = room.y * 5 + room.ysize / 2; + minDist = dist; + } + } while (room.getNext()); + + room = getRoom(area, x, y); + + if (room) { + CollMap.addRoom(room); + + return this.getNearestWalkable(x, y, 20, 4); + } + + 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; - for (i = 0; i < 3; i += 1) { + for (i = 0; i < 5; i += 1) { unit = getUnit(type, id); if (unit) { break; } - delay(100); + delay(200); } if (!unit) { - throw new Error("useUnit: Unit not found."); + throw new Error("useUnit: Unit not found. ID: " + id); } for (i = 0; i < 3; i += 1) { - this.moveToUnit(unit); - unit.interact(); + if (getDistance(me, unit) > 5) { + this.moveToUnit(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(400); + if ((!targetArea && me.area !== preArea) || me.area === targetArea) { + delay(100); return true; } @@ -467,221 +745,322 @@ MainLoop: 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 - useWaypoint: function (targetArea, check) { - // Check if target area has a waypoint - if (this.wpAreas.indexOf(targetArea) < 0) { - throw new Error("useWaypoint: Invalid area."); - } + /* + 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: " + targetArea); + case null: + case "random": + check = true; - // We're already there - if (me.area === targetArea) { - return true; - } + break; + default: + if (typeof targetArea !== "number") { + throw new Error("useWaypoint: Invalid targetArea parameter"); + } - var i, tick, wp; + if (this.wpAreas.indexOf(targetArea) < 0) { + throw new Error("useWaypoint: Invalid area"); + } - if (me.inTown) { - Town.move("waypoint"); + break; } - wp = getUnit(2, "waypoint"); - - if (!wp) { - Town.move("stash"); - Town.move("waypoint"); + var i, tick, wp; - wp = getUnit(2, "waypoint"); + for (i = 0; i < 12; i += 1) { + if (me.area === targetArea || me.dead) { + break; + } - if (!wp) { - throw new Error("Pather.useWaypoint: Failed to find waypoint."); + if (me.inTown) { + Town.move("waypoint"); } - } - for (i = 0; i < 5; i += 1) { - if (check) { - this.moveToUnit(wp); - wp.interact(); // TODO: Telekinesis option + wp = getUnit(UnitType.Object, "waypoint"); - tick = getTickCount(); + if (wp && wp.area === me.area) { + if (!me.inTown && getDistance(me, wp) > 7) { + this.moveToUnit(wp); + } + + if (check || Config.WaypointMenu) { + if (getDistance(me, wp) > 5) { + this.moveToUnit(wp); + } + + Misc.click(0, 0, wp); + + tick = getTickCount(); + + while (getTickCount() - tick < Math.max(Math.round((i + 1) * 1000 / (i / 5 + 1)), me.ping * 2)) { + if (getUIFlag(UIFlags.waypoint)) { // Waypoint screen is open + delay(500); + + switch (targetArea) { + case "random": + while (true) { + targetArea = this.wpAreas[rand(0, this.wpAreas.length - 1)]; + + // get a valid wp, avoid towns + if ([Areas.Act1.Rogue_Encampment, Areas.Act2.Lut_Gholein, Areas.Act3.Kurast_Docktown, Areas.Act4.The_Pandemonium_Fortress, Areas.Act5.Harrogath].indexOf(targetArea) === -1 && getWaypoint(this.wpAreas.indexOf(targetArea))) { + break; + } + + delay(5); + } + + break; + case null: + me.cancel(); + + return true; + } - while (getTickCount() - tick < 2000) { - if (getUIFlag(0x14)) { // Waypoint screen is open - if (!getWaypoint(this.wpAreas.indexOf(targetArea))) { - throw new Error("useWaypoint: You don't have the waypoint"); + if (!getWaypoint(this.wpAreas.indexOf(targetArea))) { + me.cancel(); + me.overhead("Trying to get the waypoint"); + + if (this.getWP(targetArea)) { + return true; + } + + throw new Error("Pather.useWaypoint: Failed to go to waypoint"); + } + + break; } - break; + delay(10); } - delay(10); + if (!getUIFlag(UIFlags.waypoint)) { + print("waypoint retry " + (i + 1)); + this.moveTo(me.x + rand(-5, 5), me.y + rand(-5, 5)); + Packet.flash(me.gid); + + continue; + } } - } - if (me.inTown) { - Town.move("waypoint"); - } + if (!check || getUIFlag(UIFlags.waypoint)) { + delay(200); + wp.interact(targetArea); - if (getUIFlag(0x14) || !check) { - wp.interact(targetArea); + tick = getTickCount(); - tick = getTickCount(); + while (getTickCount() - tick < Math.max(Math.round((i + 1) * 1000 / (i / 5 + 1)), me.ping * 2)) { + if (me.area === targetArea) { + delay(100); - while (getTickCount() - tick < 2000) { - if (me.area === targetArea) { - delay(500); + return true; + } - return true; + delay(10); } - delay(10); + me.cancel(); // In case lag causes the wp menu to stay open } - } - this.moveTo(me.x + rand(-1, 1) * 4, me.y + rand(-1, 1) * 4); // In case of client/server desync + Packet.flash(me.gid); - if (i > 1) { // Activate check if we fail direct interact twice - check = true; + if (i > 1) { // Activate check if we fail direct interact twice + check = true; + } + } else { + Packet.flash(me.gid); } - if (i > 2) { // Try to get unstuck - Town.move("stash"); - } + delay(200 + me.ping); } - throw new Error("Pather.useWaypoint: Failed to use waypoint"); + 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, - tpTome = me.findItem("tbk", 0, 3); - - if (!tpTome) { - throw new Error("makePortal: No TP tomes."); - } - - if (!tpTome.getStat(70)) { - throw new Error("makePortal: No scrolls."); - } + var i, portal, oldPortal, oldGid, tick, tpTome; - /* 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"); + for (i = 0; i < 5; i += 1) { + if (me.dead) { + break; + } - if (oldPortal) { - do { - if (oldPortal.getParent() === me.name) { - oldGid = oldPortal.gid; - } - } while (!oldGid && oldPortal.getNext()); - } + tpTome = me.findItem("tbk", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory); - for (i = 0; i < 200; i += 1) { - if (me.mode === 17) { - break; + if (!tpTome) { + throw new Error("makePortal: No TP tomes."); } - if (i % 50 === 0) { - tpTome.interact(); + if (!tpTome.getStat(Stats.quantity)) { + throw new Error("makePortal: No scrolls."); } - portal = getUnit(2, "portal"); + oldPortal = getUnit(UnitType.Object, "portal"); - if (portal) { + if (oldPortal) { do { - if (portal.getParent() === me.name && portal.gid !== oldGid) { - return use ? this.usePortal(null, null, portal) : true; + if (oldPortal.getParent() === me.name) { + oldGid = oldPortal.gid; + + break; } - } while (portal.getNext()); + } while (oldPortal.getNext()); + } + + tpTome.interact(); + + tick = getTickCount(); + +MainLoop: + while (getTickCount() - tick < Math.max(500 + i * 100, me.ping * 2 + 100)) { + portal = getUnit(UnitType.Object, "portal"); + + if (portal) { + do { + if (portal.getParent() === me.name && portal.gid !== oldGid) { + if (use) { + if (this.usePortal(null, null, copyUnit(portal))) { + return true; + } + + break MainLoop; // don't spam usePortal + } else { + return copyUnit(portal); + } + } + } while (portal.getNext()); + } + + delay(10); } - delay(20); + 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 (me.inTown) { - me.cancel(); + if (targetArea && me.area === targetArea) { + return true; } + me.cancel(); + var i, tick, portal, useTK, preArea = me.area; - if (unit) { - portal = unit; - } else { - portal = this.getPortal(targetArea, owner); - } - - if (!portal) { - return false; - } - - useTK = me.classid === 1 && me.getSkill(43, 1) && me.inTown && portal.getParent(); + for (i = 0; i < 10; i += 1) { + if (me.dead) { + break; + } - if (useTK) { - if (getDistance(me, portal) > 14) { - Attack.getIntoPosition(portal, 14, 0x4); + if (i > 0 && owner && me.inTown) { + Town.move("portalspot"); } - } else if (getDistance(me, portal) > 3) { - this.moveToUnit(portal); - } - for (i = 0; i < 5; i += 1) { - /*if (portal.mode !== 2 && !portal.getParent()) { // Arcane Sanctuary, maybe some other portals - portal.interact(); + portal = unit ? copyUnit(unit) : this.getPortal(targetArea, owner); - tick = getTickCount(); + if (portal) { + if (i === 0) { + useTK = me.classid === ClassID.Sorceress && me.getSkill(Skills.Sorceress.Telekinesis, 1) && me.inTown && portal.getParent(); + } - while (getTickCount() - tick < 1000) { - if (portal.mode === 2) { - i = 0; + if (portal.area === me.area) { + if (useTK) { + if (getDistance(me, portal) > 13) { + Attack.getIntoPosition(portal, 13, 0x4); + } - break; - } + Skill.cast(Skills.Sorceress.Telekinesis, 0, portal); + } else { + if (getDistance(me, portal) > 5) { + this.moveToUnit(portal); + } - delay(10); + if (i < 2) { + sendPacket(1, 0x13, 4, 0x2, 4, portal.gid); + } else { + Misc.click(0, 0, portal); + } + } } - continue; - }*/ + if (portal.classid === UniqueObjectIds.Arcane_Portal && portal.mode !== ObjectModes.Opened) { // Portal to/from Arcane + Misc.click(0, 0, portal); - if (useTK) { - Skill.cast(43, 0, portal); - } else { - portal.interact(); - } + tick = getTickCount(); - tick = getTickCount(); + while (getTickCount() - tick < 2000) { + if (portal.mode === ObjectModes.Opened || me.area === Areas.Act2.Arcane_Sanctuary) { + break; + } - while (getTickCount() - tick < 1000) { - if (me.area !== preArea) { - delay(300); + delay(10); + } + } - return true; + tick = getTickCount(); + + while (getTickCount() - tick < Math.max(Math.round((i + 1) * 1000 / (i / 5 + 1)), me.ping * 2)) { + if (me.area !== preArea) { + delay(100); + + return true; + } + + delay(10); } - delay(10); + if (i > 1) { + Packet.flash(me.gid); + + useTK = false; + } + } else { + Packet.flash(me.gid); } - //this.moveTo(me.x + rand(-1, 1) * 3, me.y + rand(-1, 1) * 3); // In case of client/server desync + 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"); + var portal = getUnit(UnitType.Object, "portal"); if (portal) { do { @@ -699,7 +1078,7 @@ MainLoop: } break; - default: // Pather.usePortal(null, owner) - any blue portal belonging to owner OR Pather.usePortal(area, owner) - blue portal mathcing area and owner + default: // Pather.usePortal(null, owner) - any blue portal belonging to owner OR Pather.usePortal(area, owner) - blue portal matching area and owner if (portal.getParent() === owner && (owner === me.name || Misc.inMyParty(owner))) { return copyUnit(portal); } @@ -713,17 +1092,29 @@ MainLoop: return false; }, - getNearestWalkable: function (x, y, range, step) { + /* + 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; } + if (coll === undefined) { + coll = 0x1; + } + var i, j, distance = 1, result = false; // Check if the original spot is valid - if (this.checkSpot(x, y)) { + if (this.checkSpot(x, y, coll, false, size)) { result = [x, y]; } @@ -732,14 +1123,12 @@ MainLoop: for (i = -distance; i <= distance; i += 1) { 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)) { - continue; - } - - if (this.checkSpot(x + i, y + j)) { - result = [x + i, y + j]; + if (Math.abs(i) >= Math.abs(distance) || Math.abs(j) >= Math.abs(distance)) { + if (this.checkSpot(x + i, y + j, coll, false, size)) { + result = [x + i, y + j]; - break MainLoop; + break MainLoop; + } } } } @@ -752,19 +1141,492 @@ MainLoop: return result; }, - checkSpot: function (x, y) { + /* + 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; - for (dx = -1; dx <= 1; dx += 1) { - for (dy = -1; dy <= 1; dy += 1) { - value = CollMap.getColl(x + dx, y + dy); + if (coll === undefined) { + coll = 0x1; + } - if (value !== 0 && value !== 16) { - return false; + 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); + + if (value & coll) { + return false; + } + } + } + } + + return true; + }, + + /* + Pather.accessToAct(act); + act - the act number to check for access + */ + accessToAct: function (act) { + switch (act) { + // Act 1 is always accessible + case 1: + return true; + // For the other acts, check the "Able to go to Act *" quests + case 2: + return me.getQuest(Quests.Act1.Able_to_go_to_Act_II, 0) === 1; + case 3: + return me.getQuest(Quests.Act2.Able_to_go_to_Act_III, 0) === 1; + case 4: + return me.getQuest(Quests.Act3.Able_to_go_to_Act_IV, 0) === 1; + case 5: + return me.getQuest(Quests.Act4.Able_to_go_to_Act_V, 0) === 1; + default: + return false; + } + }, + + /* + 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 = [UniqueObjectIds.Waypoint_Portal, UniqueObjectIds.Waypointi_Inner_Hell, UniqueObjectIds.Waypoint, UniqueObjectIds.WildernessWaypoint, UniqueObjectIds.Act3Waypoint_Town, UniqueObjectIds.Waypointh, + UniqueObjectIds.Waypoint_Celler, UniqueObjectIds.SewerWaypoint, UniqueObjectIds.TravincalWaypoint, UniqueObjectIds.PandamoniaWaypoint, UniqueObjectIds.VallyWaypoint, UniqueObjectIds.Waypoint2, + UniqueObjectIds.BaalWaypoint, UniqueObjectIds.WildernessWaypoint2, UniqueObjectIds.IcecaveWaypoint, UniqueObjectIds.TempleWaypoint]; + + if (area !== me.area) { + this.journeyTo(area); + } + + for (i = 0; i < wpIDs.length; i += 1) { + preset = getPresetUnit(area, UnitType.Object, wpIDs[i]); + + if (preset) { + this.moveToUnit(preset, 0, 0, clearPath); + + wp = getUnit(UnitType.Object, "waypoint"); + + if (wp) { + for (j = 0; j < 10; j += 1) { + Misc.click(0, 0, wp); + //wp.interact(); + + if (getUIFlag(UIFlags.waypoint)) { + delay(500); + me.cancel(); + + return true; + } + + delay(500); + } + } + } + } + + return false; + }, + + /* + Pather.journeyTo(area); + area - the id of area to move to + */ + journeyTo: function (area) { + var i, special, unit, tick, target; + + target = this.plotCourse(area, me.area); + + print(target.course); + + if (target.useWP) { + Town.goToTown(); + } + + // handle variable flayer jungle entrances + if (target.course.indexOf(Areas.Act3.Flayer_Jungle) > -1) { + Town.goToTown(3); // without initiated act, getArea().exits will crash + + special = getArea(Areas.Act3.Flayer_Jungle); + + if (special) { + special = special.exits; + + for (i = 0; i < special.length; i += 1) { + if (special[i].target === Areas.Act3.Great_Marsh) { + target.course.splice(target.course.indexOf(Areas.Act3.Flayer_Jungle), 0, Areas.Act3.Great_Marsh); // add great marsh if needed + + break; + } + } + } + } + + while (target.course.length) { + if (!me.inTown) { + Precast.doPrecast(false); + } + + if (this.wpAreas.indexOf(me.area) > -1 && !getWaypoint(this.wpAreas.indexOf(me.area))) { + this.getWP(me.area); + } + + if (me.inTown && this.wpAreas.indexOf(target.course[0]) > -1 && getWaypoint(this.wpAreas.indexOf(target.course[0]))) { + this.useWaypoint(target.course[0], !this.plotCourse_openedWpMenu); + Precast.doPrecast(false); + } else if (me.area === Areas.Act5.Harrogath && target.course[0] === Areas.Act5.Bloody_Foothills) { // Harrogath -> Bloody Foothills + this.moveTo(5026, 5095); + + unit = getUnit(UnitType.Object, UniqueObjectIds.Town_Main_Gate); // Gate + + if (unit) { + for (i = 0; i < 3; i += 1) { + Misc.click(0, 0, unit); + //unit.interact(); + + tick = getTickCount(); + + while (getTickCount() - tick < 3000) { + if (unit.mode === 2) { + delay(1000); + + break; + } + + delay(10); + } + } + } + + this.moveToExit(target.course[0], true); + } else if (me.area === Areas.Act1.Stony_Field && target.course[0] === Areas.Act1.Tristram) { // Stony Field -> Tristram + this.moveToPreset(me.area, UnitType.Monster_or_NPC, SuperUniques.Rakanishu, 0, 0, false, true); + + for (i = 0; i < 5; i += 1) { + if (this.usePortal(Areas.Act1.Tristram)) { + break; + } + + delay(1000); + } + } else if (me.area === Areas.Act2.Lut_Gholein && target.course[0] === Areas.Act2.A2_Sewers_Level_1) { // Lut Gholein -> Sewers Level 1 (use Trapdoor) + this.moveToPreset(me.area, UnitType.Warp, UniqueObjectIds.StoneGamma); // 19 + this.useUnit(UnitType.Warp, UniqueObjectIds.StoneGamma, Areas.Act2.A2_Sewers_Level_1); + } else if (me.area === Areas.Act2.Arcane_Sanctuary && target.course[0] === Areas.Act2.Canyon_Of_The_Magi) { // Arcane Sanctuary -> Canyon of the Magi + this.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Horazons_Journal); + + for (i = 0; i < 5; i += 1) { + unit = getUnit(UnitType.Object, UniqueObjectIds.Horazons_Journal); + + Misc.click(0, 0, unit); + delay(1000); + me.cancel(); + + if (this.usePortal(Areas.Act2.Canyon_Of_The_Magi)) { + break; + } } + } else if (me.area === Areas.Act2.Palace_Cellar_Level_3 && target.course[0] === Areas.Act2.Arcane_Sanctuary) { // Palace -> Arcane + this.moveTo(10073, 8670); + this.usePortal(null); + } else if (me.area === Areas.Act5.Harrogath && target.course[0] === Areas.Act5.Nihlathaks_Temple) { // Harrogath -> Nihlathak's Temple + Town.move("anya"); + this.usePortal(Areas.Act5.Nihlathaks_Temple); + } else if (me.area === Areas.Act5.Frigid_Highlands && target.course[0] === Areas.Act5.Abaddon) { // Abaddon + this.moveToPreset(Areas.Act5.Frigid_Highlands, UnitType.Object, 60); + this.usePortal(Areas.Act5.Abaddon); + } else if (me.area === Areas.Act5.Arreat_Plateau && target.course[0] === Areas.Act5.Pit_Of_Acheron) { // Pits of Archeon + this.moveToPreset(Areas.Act5.Arreat_Plateau, UnitType.Object, 60); + this.usePortal(Areas.Act5.Pit_Of_Acheron); + } else if (me.area === Areas.Act5.Frozen_Tundra && target.course[0] === Areas.Act5.Infernal_Pit) { // Infernal Pit + this.moveToPreset(Areas.Act5.Frozen_Tundra, UnitType.Object, 60); + this.usePortal(Areas.Act5.Infernal_Pit); + } else { + this.moveToExit(target.course[0], true); } + + target.course.shift(); + } + + return me.area === area; + }, + + plotCourse_openedWpMenu: false, + + /* + Pather.plotCourse(dest, src); + dest - destination area id + src - starting area id + */ + plotCourse: function (dest, src) { + var node, prevArea, + useWP = false, + arr = [], + previousAreas = [Areas.None, Areas.None, Areas.Act1.Rogue_Encampment, Areas.Act1.Blood_Moor, Areas.Act1.Cold_Plains, Areas.Act1.Underground_Passage_Level_1, Areas.Act1.Dark_Wood, + Areas.Act1.Black_Marsh, Areas.Act1.Blood_Moor, Areas.Act1.Cold_Plains, Areas.Act1.Stony_Field, Areas.Act1.Black_Marsh, Areas.Act1.Tamoe_Highland, Areas.Act1.Cave_Level_1, + Areas.Act1.Underground_Passage_Level_1, Areas.Act1.Hole_Level_1, Areas.Act1.Pit_Level_1, Areas.Act1.Cold_Plains, Areas.Act1.Burial_Grounds, Areas.Act1.Burial_Grounds, + Areas.Act1.Black_Marsh, Areas.Act1.Forgotten_Tower, Areas.Act1.Tower_Cellar_Level_1, Areas.Act1.Tower_Cellar_Level_2, Areas.Act1.Tower_Cellar_Level_3, + Areas.Act1.Tower_Cellar_Level_4, Areas.Act1.Tamoe_Highland, Areas.Act1.Monastery_Gate, Areas.Act1.Outer_Cloister, Areas.Act1.Barracks, Areas.Act1.Jail_Level_1, + Areas.Act1.Jail_Level_2, Areas.Act1.Jail_Level_3, Areas.Act1.Inner_Cloister, Areas.Act1.Cathedral, Areas.Act1.Catacombs_Level_1, Areas.Act1.Catacombs_Level_2, + Areas.Act1.Catacombs_Level_3, Areas.Act1.Stony_Field, Areas.Act1.Rogue_Encampment, Areas.Act1.Rogue_Encampment, Areas.Act2.Lut_Gholein, Areas.Act2.Rocky_Waste, + Areas.Act2.Dry_Hills, Areas.Act2.Far_Oasis, Areas.Act2.Lost_City, Areas.Act2.Arcane_Sanctuary, Areas.Act2.Lut_Gholein, Areas.Act2.A2_Sewers_Level_1, Areas.Act2.A2_Sewers_Level_2, + Areas.Act2.Lut_Gholein, Areas.Act2.Harem_Level_1, Areas.Act2.Harem_Level_2, Areas.Act2.Palace_Cellar_Level_1, Areas.Act2.Palace_Cellar_Level_2, Areas.Act2.Rocky_Waste, + Areas.Act2.Dry_Hills, Areas.Act2.Halls_Of_The_Dead_Level_1, Areas.Act2.Valley_Of_Snakes, Areas.Act2.Stony_Tomb_Level_1, Areas.Act2.Halls_Of_The_Dead_Level_2, + Areas.Act2.Claw_Viper_Temple_Level_1, Areas.Act2.Far_Oasis, Areas.Act2.Maggot_Lair_Level_1, Areas.Act2.Maggot_Lair_Level_2, Areas.Act2.Lost_City, Areas.Act2.Canyon_Of_The_Magi, + Areas.Act2.Canyon_Of_The_Magi, Areas.Act2.Canyon_Of_The_Magi, Areas.Act2.Canyon_Of_The_Magi, Areas.Act2.Canyon_Of_The_Magi, Areas.Act2.Canyon_Of_The_Magi, + Areas.Act2.Canyon_Of_The_Magi, Areas.Act1.Rogue_Encampment, Areas.Act2.Palace_Cellar_Level_3, Areas.Act1.Rogue_Encampment, Areas.Act3.Kurast_Docktown, Areas.Act3.Spider_Forest, + Areas.Act3.Spider_Forest, Areas.Act3.Flayer_Jungle, Areas.Act3.Lower_Kurast, Areas.Act3.Kurast_Bazaar, Areas.Act3.Upper_Kurast, Areas.Act3.Kurast_Causeway, + Areas.Act3.Spider_Forest, Areas.Act3.Spider_Forest, Areas.Act3.Flayer_Jungle, Areas.Act3.Swampy_Pit_Level_1, Areas.Act3.Flayer_Jungle, Areas.Act3.Flayer_Dungeon_Level_1, + Areas.Act3.Swampy_Pit_Level_2, Areas.Act3.Flayer_Dungeon_Level_2, Areas.Act3.Kurast_Bazaar, Areas.Act3.A3_Sewers_Level_1, Areas.Act3.Kurast_Bazaar, Areas.Act3.Kurast_Bazaar, + Areas.Act3.Upper_Kurast, Areas.Act3.Upper_Kurast, Areas.Act3.Kurast_Causeway, Areas.Act3.Kurast_Causeway, Areas.Act3.Travincal, Areas.Act3.Durance_Of_Hate_Level_1, + Areas.Act3.Durance_Of_Hate_Level_2, Areas.Act1.Rogue_Encampment, Areas.Act4.The_Pandemonium_Fortress, Areas.Act4.Outer_Steppes, Areas.Act4.Plains_Of_Despair, + Areas.Act4.City_Of_The_Damned, Areas.Act4.River_Of_Flame, Areas.Act1.Rogue_Encampment, Areas.Act5.Harrogath, Areas.Act5.Bloody_Foothills, Areas.Act5.Frigid_Highlands, + Areas.Act5.Arreat_Plateau, Areas.Act5.Crystalized_Passage, Areas.Act5.Crystalized_Passage, Areas.Act5.Glacial_Trail, Areas.Act5.Glacial_Trail, Areas.Act5.Frozen_Tundra, + Areas.Act5.Ancients_Way, Areas.Act5.Ancients_Way, Areas.Act5.Harrogath, Areas.Act5.Nihlathaks_Temple, Areas.Act5.Halls_Of_Anguish, Areas.Act5.Halls_Of_Pain, + Areas.Act5.Frigid_Highlands, Areas.Act5.Arreat_Plateau, Areas.Act5.Frozen_Tundra, Areas.Act5.Arreat_Summit, Areas.Act5.The_Worldstone_Keep_Level_1, + Areas.Act5.The_Worldstone_Keep_Level_2, Areas.Act5.The_Worldstone_Keep_Level_3, Areas.Act5.Throne_Of_Destruction, Areas.Act5.Harrogath, Areas.Act5.Harrogath, + Areas.Act5.Harrogath, Areas.Act5.Harrogath], + visitedNodes = [], + toVisitNodes = [{from: dest, to: null}]; + + if (!src) { + src = me.area; + } + + if (!this.plotCourse_openedWpMenu && me.inTown && Pather.useWaypoint(null)) { + this.plotCourse_openedWpMenu = true; + } + + while (toVisitNodes.length > 0) { + node = toVisitNodes[0]; + + // If we've already visited it, just move on + if (visitedNodes[node.from] === undefined) { + visitedNodes[node.from] = node.to; + + if (this.areasConnected(node.from, node.to)) { + // If we have this wp we can start from there + 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)) + ) { + if (node.from !== src) { + useWP = true; + } + + src = node.from; + } + + // We found it, time to go + if (node.from === src) { + break; + } + + if ((prevArea = previousAreas[node.from]) !== 0 && visitedNodes.indexOf(prevArea) === -1) { + toVisitNodes.push({from: prevArea, to: node.from}); + } + + for (prevArea = 1; prevArea < previousAreas.length; prevArea += 1) { + // Only interested in those connected to node + if (previousAreas[prevArea] === node.from && visitedNodes.indexOf(prevArea) === -1) { + toVisitNodes.push({from: prevArea, to: node.from}); + } + } + } + + toVisitNodes.shift(); + } else { + useWP = true; + } + } + + arr.push(src); + + node = src; + + while (node !== dest && node !== undefined) { + arr.push(node = visitedNodes[node]); + } + + // Something failed + if (node === undefined) { + return false; + } + + return {course: arr, useWP: useWP}; + }, + + /* + Pather.areasConnected(src, dest); + dest - destination area id + src - starting area id + */ + areasConnected: function (src, dest) { + if (src === Areas.Act2.Canyon_Of_The_Magi && dest === Areas.Act2.Arcane_Sanctuary) { + return false; } return true; + }, + + /* + Pather.getAreaName(area); + area - id of the area to get the name for + */ + getAreaName: function (area) { + var areas = [ + "None", + "Rogue Encampment", + "Blood Moor", + "Cold Plains", + "Stony Field", + "Dark Wood", + "Black Marsh", + "Tamoe Highland", + "Den Of Evil", + "Cave Level 1", + "Underground Passage Level 1", + "Hole Level 1", + "Pit Level 1", + "Cave Level 2", + "Underground Passage Level 2", + "Hole Level 2", + "Pit Level 2", + "Burial Grounds", + "Crypt", + "Mausoleum", + "Forgotten Tower", + "Tower Cellar Level 1", + "Tower Cellar Level 2", + "Tower Cellar Level 3", + "Tower Cellar Level 4", + "Tower Cellar Level 5", + "Monastery Gate", + "Outer Cloister", + "Barracks", + "Jail Level 1", + "Jail Level 2", + "Jail Level 3", + "Inner Cloister", + "Cathedral", + "Catacombs Level 1", + "Catacombs Level 2", + "Catacombs Level 3", + "Catacombs Level 4", + "Tristram", + "Moo Moo Farm", + "Lut Gholein", + "Rocky Waste", + "Dry Hills", + "Far Oasis", + "Lost City", + "Valley Of Snakes", + "Canyon Of The Magi", + "Sewers Level 1", + "Sewers Level 2", + "Sewers Level 3", + "Harem Level 1", + "Harem Level 2", + "Palace Cellar Level 1", + "Palace Cellar Level 2", + "Palace Cellar Level 3", + "Stony Tomb Level 1", + "Halls Of The Dead Level 1", + "Halls Of The Dead Level 2", + "Claw Viper Temple Level 1", + "Stony Tomb Level 2", + "Halls Of The Dead Level 3", + "Claw Viper Temple Level 2", + "Maggot Lair Level 1", + "Maggot Lair Level 2", + "Maggot Lair Level 3", + "Ancient Tunnels", + "Tal Rashas Tomb #1", + "Tal Rashas Tomb #2", + "Tal Rashas Tomb #3", + "Tal Rashas Tomb #4", + "Tal Rashas Tomb #5", + "Tal Rashas Tomb #6", + "Tal Rashas Tomb #7", + "Duriels Lair", + "Arcane Sanctuary", + "Kurast Docktown", + "Spider Forest", + "Great Marsh", + "Flayer Jungle", + "Lower Kurast", + "Kurast Bazaar", + "Upper Kurast", + "Kurast Causeway", + "Travincal", + "Spider Cave", + "Spider Cavern", + "Swampy Pit Level 1", + "Swampy Pit Level 2", + "Flayer Dungeon Level 1", + "Flayer Dungeon Level 2", + "Swampy Pit Level 3", + "Flayer Dungeon Level 3", + "Sewers Level 1", + "Sewers Level 2", + "Ruined Temple", + "Disused Fane", + "Forgotten Reliquary", + "Forgotten Temple", + "Ruined Fane", + "Disused Reliquary", + "Durance Of Hate Level 1", + "Durance Of Hate Level 2", + "Durance Of Hate Level 3", + "The Pandemonium Fortress", + "Outer Steppes", + "Plains Of Despair", + "City Of The Damned", + "River Of Flame", + "Chaos Sanctuary", + "Harrogath", + "Bloody Foothills", + "Frigid Highlands", + "Arreat Plateau", + "Crystalline Passage", + "Frozen River", + "Glacial Trail", + "Drifter Cavern", + "Frozen Tundra", + "Ancient's Way", + "Icy Cellar", + "Arreat Summit", + "Nihlathak's Temple", + "Halls Of Anguish", + "Halls Of Pain", + "Halls Of Vaught", + "Abaddon", + "Pit Of Acheron", + "Infernal Pit", + "Worldstone Keep Level 1", + "Worldstone Keep Level 2", + "Worldstone Keep Level 3", + "Throne Of Destruction", + "The Worldstone Chamber", + "Matron's Den", + "Fogotten Sands", + "Furnace of Pain", + "Tristram"]; + + return areas[area]; } -}; \ No newline at end of file +}; diff --git a/d2bs/kolbot/libs/common/Pickit.js b/d2bs/kolbot/libs/common/Pickit.js index 1ed926616..ea2786e5a 100644 --- a/d2bs/kolbot/libs/common/Pickit.js +++ b/d2bs/kolbot/libs/common/Pickit.js @@ -4,188 +4,356 @@ * @desc handle item pickup */ + var Pickit = { - pickList: [], + gidList: [], beltSize: 1, - ignoreLog: [4, 5, 6, 22, 41, 76, 77, 78, 79, 80, 81], // Ignored item types for item logging + ignoreLog: [NTItemTypes.gold, NTItemTypes.bowquiver, NTItemTypes.crossbowquiver, NTItemTypes.scroll, NTItemTypes.key, NTItemTypes.healingpotion, NTItemTypes.manapotion, NTItemTypes.rejuvpotion, NTItemTypes.staminapotion, + NTItemTypes.antidotepotion, NTItemTypes.thawingpotion], // Ignored item types for item logging - init: function () { + init: function (notify) { var i, filename; for (i = 0; i < Config.PickitFiles.length; i += 1) { filename = "pickit/" + Config.PickitFiles[i]; - NTIPOpenFile(filename); + NTIP.OpenFile(filename, notify); } this.beltSize = Storage.BeltSize(); }, + // Returns: + // -1 - Needs iding + // 0 - Unwanted + // 1 - NTIP wants + // 2 - Cubing wants + // 3 - Runeword wants + // 4 - Pickup to sell (triggered when low on gold) checkItem: function (unit) { - var result = NTIPCheckItem(unit); + var rval = NTIP.CheckItem(unit, false, true); + + if ((unit.classid === ItemClassIds.Ral_Rune || unit.classid === ItemClassIds.Ort_Rune) && Town.repairIngredientCheck(unit)) { + return { + result: 6, + line: null + }; + } + + if (CraftingSystem.checkItem(unit)) { + return { + result: 5, + line: null + }; + } if (Cubing.checkItem(unit)) { - return 2; + return { + result: 2, + line: null + }; } if (Runewords.checkItem(unit)) { - return 3; + return { + result: 3, + line: null + }; } - return result; - }, + // If total gold is less than 10k pick up anything worth 10 gold per + // square to sell in town. + if (rval.result === 0 && Town.ignoredItemTypes.indexOf(unit.itemType) === -1 && me.gold < Config.LowGold && unit.itemType !== NTItemTypes.quest) { + // Gold doesn't take up room, just pick it up + if (unit.classid === ItemClassIds.Gold) { + return { + result: 4, + line: null + }; + } - pickItems: function () { - function ItemStats(unit) { - this.classid = unit.classid; - this.x = unit.x; - this.y = unit.y; - this.gid = unit.gid; + if (unit.getItemCost(1) / (unit.sizex * unit.sizey) >= 10) { + return { + result: 4, + line: null + }; + } } - var status, gid, item, canFit; + return rval; + }, + + pickItems: function () { + var status, item, canFit, + needMule = false, + pickList = []; Town.clearBelt(); + if (me.dead) { + return false; + } + while (!me.idle) { delay(40); } - item = getUnit(4); - this.pickList = []; + item = getUnit(UnitType.Item); if (item) { do { - if ((item.mode === 3 || item.mode === 5) && getDistance(me, item) <= Config.PickRange) { - this.pickList.push(new ItemStats(item)); + if ((item.mode === ItemModes.Item_on_ground || item.mode === ItemModes.Item_being_dropped) && getDistance(me, item) <= Config.PickRange) { + pickList.push(copyUnit(item)); } } while (item.getNext()); } - this.pickList.sort(this.sortItems); + while (pickList.length > 0) { + if (me.dead) { + return false; + } - while (this.pickList.length > 0) { - gid = this.pickList.shift().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 === ItemModes.Item_on_ground || pickList[0].mode === ItemModes.Item_being_dropped) && + (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) { - 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]) || [NTItemTypes.gold, NTItemTypes.scroll, NTItemTypes.healingpotion, NTItemTypes.manapotion, NTItemTypes.rejuvpotion].indexOf(pickList[0].itemType) > -1; - if (status && this.canPick(item)) { - // Check room, don't check gold, scrolls and potions - canFit = Storage.Inventory.CanFit(item) || [4, 22, 76, 77, 78].indexOf(item.itemType) > -1; - - if (!canFit) { - if (Config.FieldID && Town.fieldID()) { - canFit = Storage.Inventory.CanFit(item) || [4, 22, 76, 77, 78].indexOf(item.itemType) > -1; - } - } - - if (!canFit) { - print("ÿc7Trying to make room for " + item.name); + // Try to make room with FieldID + if (!canFit && Config.FieldID && Town.fieldID()) { + canFit = Storage.Inventory.CanFit(pickList[0]) || [NTItemTypes.gold, NTItemTypes.scroll, NTItemTypes.healingpotion, NTItemTypes.manapotion, NTItemTypes.rejuvpotion].indexOf(pickList[0].itemType) > -1; + } - if (!Town.visitTown()) { - print("ÿc7Not enough room for " + item.name); + // 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); - return false; + // 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. + + return this.pickItems(); } - } - if (Storage.Inventory.CanFit(item) || [4, 22, 76, 77, 78].indexOf(item.itemType) > -1) { - this.pickItem(item, status); - } else { - print("ÿc7Not enough room for " + item.name); + // Town visit failed - abort + print("ÿc7Not enough room for " + this.itemColor(pickList[0]) + pickList[0].name); + + return false; } + + // 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); + + needMule = true; + } + + // Item can fit - pick it up + if (canFit) { + this.pickItem(pickList[0], status.result, status.line); } } } + + 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"); + scriptBroadcast("quit"); } return true; }, - pickItem: function (unit, status) { - var i, picked, tick, - classid = unit.classid, - gid = unit.gid, - name = unit.name, - type = unit.itemType, - color = this.itemColor(unit), - gold = unit.getStat(14), - // TODO: Add config option for Telekinesis - useTk = me.classid === 1 && me.getSkill(43, 1) && (type === 4 || type === 22 || (type > 75 && type < 82)) && getDistance(me, unit) > 5 && getDistance(me, unit) < 20 && !checkCollision(me, unit, 0x4); + // 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 + // For low level chars that can't actually get id scrolls -> prevent an infinite loop + if (me.getStat(Stats.gold) + me.getStat(Stats.goldbank) < 100) { + return false; + } + + return true; + case 0: + break; + default: // Check if a kept item can be stashed + if (Town.canStash(items[i])) { + return true; + } + + break; + } + } + } + + return false; + }, + + pickItem: function (unit, status, keptLine) { + function ItemStats(unit) { + this.ilvl = unit.ilvl; + this.type = unit.itemType; + this.classid = unit.classid; + this.name = unit.name; + this.color = Pickit.itemColor(unit); + this.gold = unit.getStat(Stats.gold); + this.useTk = Config.UseTelekinesis && me.classid === ClassID.Sorceress && me.getSkill(Skills.Sorceress.Telekinesis, 1) && (this.type === NTItemTypes.gold || this.type === NTItemTypes.scroll || (this.type > NTItemTypes.healingpotion && this.type < NTItemTypes.smallcharm)) && + getDistance(me, unit) > 5 && getDistance(me, unit) < 20 && !checkCollision(me, unit, 0x4); + this.picked = false; + } + + var i, item, tick, gid, stats, + itemCount = me.itemcount; + + if (unit.gid) { + gid = unit.gid; + item = getUnit(UnitType.Item, -1, -1, gid); + } + + if (!item) { + return false; + } + + stats = new ItemStats(item); MainLoop: for (i = 0; i < 3; i += 1) { + if (!getUnit(4, -1, -1, gid)) { + break MainLoop; + } + + if (me.dead) { + return false; + } + while (!me.idle) { delay(40); } - if ((unit.mode !== 3 && unit.mode !== 5) || !copyUnit(unit).x) { // added invalidated unit check + if (item.mode !== ItemModes.Item_on_ground && item.mode !== ItemModes.Item_being_dropped) { break MainLoop; } - if (useTk) { - Skill.cast(43, 0, unit); - } else if (getDistance(me, unit) < 4 || Pather.moveToUnit(unit)) { - unit.interact(); + if (stats.useTk) { + Skill.cast(Skills.Sorceress.Telekinesis, 0, 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 { + sendPacket(1, 0x16, 4, 0x4, 4, item.gid, 4, 0); + } } tick = getTickCount(); - while (getTickCount() - tick < 750) { - unit = copyUnit(unit); + while (getTickCount() - tick < 1000) { + item = copyUnit(item); - if (classid === 523) { - if (!unit.getStat(14) || unit.getStat(14) < gold) { - print("ÿc7Picked up " + color + gold + " " + name); + if (stats.classid === ItemClassIds.Gold) { + if (!item.getStat(Stats.gold) || item.getStat(Stats.gold) < stats.gold) { + print("ÿc7Picked up " + stats.color + (item.getStat(Stats.gold) ? (item.getStat(Stats.gold) - stats.gold) : stats.gold) + " " + stats.name); - break MainLoop; + return true; } } - if (unit.mode !== 3 && unit.mode !== 5) { - switch (classid) { - case 529: // Scroll of Town Portal - case 530: // Scroll of Identify - print("ÿc7Picked up " + color + name + " ÿc7(" + Town.checkScrolls(classid === 529 ? "tbk" : "ibk") + "/20)"); + if (item.mode !== ItemModes.Item_on_ground && item.mode !== ItemModes.Item_being_dropped) { + switch (stats.classid) { + case ItemClassIds.Key: // Key + print("ÿc7Picked up " + stats.color + stats.name + " ÿc7(" + Town.checkKeys() + "/12)"); - break MainLoop; - } + return true; + case ItemClassIds.Scroll_Of_Town_Portal: // Scroll of Town Portal + case ItemClassIds.Scroll_Of_Identify: // Scroll of Identify + print("ÿc7Picked up " + stats.color + stats.name + " ÿc7(" + Town.checkScrolls(stats.classid === ItemClassIds.Scroll_Of_Town_Portal ? "tbk" : "ibk") + "/20)"); - if (unit.getParent() && unit.getParent().name === me.name) { - picked = true; + return true; } break MainLoop; } - delay(10); + delay(20); } + // TK failed, disable it + stats.useTk = false; + //print("pick retry"); } - if (picked) { - print("ÿc7Picked up " + color + name); + stats.picked = me.itemcount > itemCount || !!me.getItem(-1, -1, gid); + + if (stats.picked) { DataFile.updateStats("lastArea"); switch (status) { case 1: - if (this.ignoreLog.indexOf(type) === -1) { - //D2Bot.printToItemLog("Kept " + name); - Misc.logItem("Kept", unit); + 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) { + break; + } + + if (["dhn", "bey", "mbr"].indexOf(item.code) > -1 && !TorchSystem.LogOrgans) { + break; + } + + Misc.logItem("Kept", item, keptLine); } break; case 2: - Cubing.update(classid); + 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: - Runewords.update(classid, gid); + 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 + " ÿc0(ilvl " + stats.ilvl + (keptLine ? ") (" + keptLine + ")" : ")")); break; } @@ -194,58 +362,82 @@ MainLoop: return true; }, - itemColor: function (unit) { - switch (unit.itemType) { - case 4: // gold - return "ÿc4"; - case 74: // runes - return "ÿc8"; - case 76: // healing potions - return "ÿc1"; - case 77: // mana potions - return "ÿc3"; - case 78: // juvs - return "ÿc;"; + itemQualityToName: function (quality) { + var qualNames = ["", "lowquality", "normal", "superior", "magic", "set", "rare", "unique", "crafted"]; + + return qualNames[quality]; + }, + + itemColor: function (unit, type) { + if (type === undefined) { + type = true; + } + + if (type) { + switch (unit.itemType) { + case NTItemTypes.gold: // gold + return "ÿc4"; + case NTItemTypes.rune: // runes + return "ÿc8"; + case NTItemTypes.healingpotion: // healing potions + return "ÿc1"; + case NTItemTypes.manapotion: // mana potions + return "ÿc3"; + case NTItemTypes.rejuvpotion: // juvs + return "ÿc;"; + } } switch (unit.quality) { - case 4: // magic + case ItemQuality.Magic: // magic return "ÿc3"; - case 5: // set + case ItemQuality.Set: // set return "ÿc2"; - case 6: // rare + case ItemQuality.Rare: // rare return "ÿc9"; - case 7: // unique + case ItemQuality.Unique: // unique return "ÿc4"; - case 8: // crafted + case ItemQuality.Crafted: // crafted return "ÿc8"; } return "ÿc0"; }, - sortItems: function (unitA, unitB) { - // TODO: Add some kind of advanced sorting - - return getDistance(me, unitA.x, unitA.y) - getDistance(me, unitB.x, unitB.y); - }, - canPick: function (unit) { - var tome, charm, i, potion, needPots; + var tome, charm, i, potion, needPots, buffers, pottype, myKey, key; + + switch (unit.classid) { + case ItemClassIds.Staff_of_Kings: // Staff of Kings + case ItemClassIds.Khalims_Flail: // Khalim's Flail + case ItemClassIds.Viper_Amulet: // Viper Amulet + case ItemClassIds.A_Jade_Figurine: // Jade Figurine + case ItemClassIds.Horadric_Cube: // Cube + case ItemClassIds.Mephistos_Soulstone: // Mephisto's Soulstone + case ItemClassIds.Book_Of_Skill: // Book of Skill + case ItemClassIds.Khalims_Eye: // Khalim's Eye + case ItemClassIds.Khalims_Heart: // Khalim's Heart + case ItemClassIds.Khalims_Brain: // 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) + case NTItemTypes.gold: // Gold + if (me.getStat(Stats.gold) === me.getStat(Stats.level) * 10000) { // Check current gold vs max capacity (cLvl*10000) return false; // Skip gold if full } - break; - case 22: // Scroll + break; + case NTItemTypes.scroll: // Scroll tome = me.getItem(unit.classid - 11, 0); // 518 - Tome of Town Portal or 519 - Tome of Identify, mode 0 - inventory/stash if (tome) { do { - if (tome.location === 3 && tome.getStat(70) === 20) { // In inventory, contains 20 scrolls + if (tome.location === ItemLocation.Inventory && tome.getStat(Stats.quantity) === 20) { // In inventory, contains 20 scrolls return false; // Skip a scroll if its tome is full } } while (tome.getNext()); @@ -254,15 +446,32 @@ MainLoop: } break; - case 82: // Small Charm - case 83: // Large Charm - case 84: // Grand Charm - if (unit.quality === 7) { // Unique - charm = me.getItem(unit.classid, 0); + case NTItemTypes.key: // Key (new 26.1.2013) + if (me.classid === ClassID.Assassin) { // Assassins don't ever need keys + return false; + } + + myKey = me.getItem(ItemClassIds.Key, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); // 543 = key + key = getUnit(4, -1, -1, unit.gid); // Passed argument isn't an actual unit, we need to get it + + if (myKey && key) { + do { + if (myKey.location === ItemLocation.Inventory && myKey.getStat(Stats.quantity) + key.getStat(Stats.quantity) > 12) { + return false; + } + } while (myKey.getNext()); + } + + break; + case NTItemTypes.smallcharm: // Small Charm + case NTItemTypes.mediumcharm: // Large Charm + case NTItemTypes.largecharm: // Grand Charm + if (unit.quality === ItemQuality.Unique) { // Unique + charm = me.getItem(unit.classid, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); if (charm) { do { - if (charm.quality === 7) { + if (charm.quality === ItemQuality.Unique) { return false; // Skip Gheed's Fortune, Hellfire Torch or Annihilus if we already have one } } while (charm.getNext()); @@ -270,9 +479,9 @@ MainLoop: } break; - case 76: // Healing Potion - case 77: // Mana Potion - case 78: // Rejuvenation Potion + case NTItemTypes.healingpotion: // Healing Potion + case NTItemTypes.manapotion: // Mana Potion + case NTItemTypes.rejuvpotion: // Rejuvenation Potion needPots = 0; for (i = 0; i < 4; i += 1) { @@ -281,7 +490,7 @@ MainLoop: } } - potion = me.getItem(-1, 2); + potion = me.getItem(-1, ItemLocation.Belt); if (potion) { do { @@ -291,26 +500,63 @@ MainLoop: } while (potion.getNext()); } - if (needPots < 1) { - // For juvs in inventory - if (Config.RejuvBuffer && unit.itemType === 78) { - if (!Storage.Inventory.CanFit(unit)) { - return false; - } + if (needPots < 1 && this.checkBelt()) { + buffers = ["HPBuffer", "MPBuffer", "RejuvBuffer"]; + + for (i = 0; i < buffers.length; i += 1) { + if (Config[buffers[i]]) { + switch (buffers[i]) { + case "HPBuffer": + pottype = NTItemTypes.healingpotion; + + break; + case "MPBuffer": + pottype = NTItemTypes.manapotion; - needPots = Config.RejuvBuffer; - potion = me.getItem(-1, 0); + break; + case "RejuvBuffer": + pottype = NTItemTypes.rejuvpotion; - if (potion) { - do { - if (potion.itemType === 78 && potion.location === 3) { - needPots -= 1; + break; + } + + if (unit.itemType === pottype) { + if (!Storage.Inventory.CanFit(unit)) { + return false; + } + + needPots = Config[buffers[i]]; + potion = me.getItem(-1, ItemLocation.Ground); + + if (potion) { + do { + if (potion.itemType === pottype && potion.location === ItemLocation.Inventory) { + needPots -= 1; + } + } while (potion.getNext()); } - } while (potion.getNext()); + } } } } + if (needPots < 1) { + potion = me.getItem(); + + if (potion) { + do { + if (potion.itemType === unit.itemType && ((potion.mode === ItemModes.Item_In_Inventory_Stash_Cube_Or_Store && potion.location === ItemLocation.Inventory) || potion.mode === ItemModes.Item_in_belt)) { + if (potion.classid < unit.classid) { + potion.interact(); + needPots += 1; + + break; + } + } + } while (potion.getNext()); + } + } + if (needPots < 1) { return false; } @@ -325,18 +571,63 @@ MainLoop: return true; }, + checkBelt: function () { + var check = 0, + item = me.getItem(-1, ItemLocation.Belt); + + if (item) { + do { + if (item.x < 4) { + check += 1; + } + } while (item.getNext()); + } + + 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 === NTItemTypes.rune || unitA.quality === ItemQuality.Unique) { + return -1; + } + + if (unitB.itemType === NTItemTypes.rune || unitB.quality === ItemQuality.Unique) { + 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(UnitType.Item, -1, -1, gid); + + if (item && (item.mode === ItemModes.Item_on_ground || item.mode === ItemModes.Item_being_dropped) && Town.ignoredItemTypes.indexOf(item.itemType) === -1 && getDistance(me, item) <= Config.PickRange) { + itemList.push(copyUnit(item)); + } + } + + while (itemList.length > 0) { + itemList.sort(this.sortFastPickItems); - while (gidList.length > 0) { - gid = gidList.shift(); - item = getUnit(4, -1, -1, gid); + item = copyUnit(itemList.shift()); - if (item && (item.mode === 3 || item.mode === 5) && getDistance(me, item) <= Config.PickRange) { + // Check if the item unit is still valid + if (item.x !== undefined) { status = this.checkItem(item); - if (status && this.canPick(item) && (Storage.Inventory.CanFit(item) || [4, 22, 76, 77, 78].indexOf(item.itemType) > -1)) { - this.pickItem(item, status); + if (status.result && this.canPick(item) && (Storage.Inventory.CanFit(item) || [NTItemTypes.gold, NTItemTypes.scroll, NTItemTypes.healingpotion, NTItemTypes.manapotion, NTItemTypes.rejuvpotion].indexOf(item.itemType) > -1)) { + this.pickItem(item, status.result, status.line); } } } diff --git a/d2bs/kolbot/libs/common/Precast.js b/d2bs/kolbot/libs/common/Precast.js index a7782b1aa..670864f12 100644 --- a/d2bs/kolbot/libs/common/Precast.js +++ b/d2bs/kolbot/libs/common/Precast.js @@ -6,15 +6,23 @@ var Precast = new function () { this.haveCTA = -1; + this.BODuration = 0; + this.BOTick = 0; this.weaponSwitch = function (slot) { - if (me.gametype === 0) { + if (me.gametype === GameType.Classic) { return true; } + if (slot === -1) { + this.BOSwitch(); + + slot = this.haveCTA; + } + var i, tick; - if (!arguments.length) { + if (slot === undefined) { slot = me.weaponswitch === 0 ? 1 : 0; } else if (me.weaponswitch === slot) { return true; @@ -22,14 +30,14 @@ var Precast = new function () { delay(500); - for (i = 0; i < 10; i += 1) { + for (i = 0; i < 5; i += 1) { weaponSwitch(); tick = getTickCount(); - while (getTickCount() - tick < 2000) { + while (getTickCount() - tick < 2000 + me.ping) { if (me.weaponswitch === slot) { - delay(me.ping + 1); + //delay(me.ping + 1); return true; } @@ -42,17 +50,21 @@ var Precast = new function () { }; this.precastCTA = function (force) { - if (!force && me.getState(32)) { + if (!force && me.getState(States.BATTLEORDERS)) { return true; } - if (me.gametype === 0 || me.classid === 4 || me.inTown) { + if (me.gametype === GameType.Classic || me.classid === ClassID.Barbarian || me.inTown) { return false; } if (this.BOSwitch()) { - Skill.cast(155, 0); // Battle Command - Skill.cast(149, 0); // Battle Orders + Skill.cast(Skills.Barbarian.Battle_Command, 0); // Battle Command + Skill.cast(Skills.Barbarian.Battle_Orders, 0); // Battle Orders + + this.BODuration = (20 + me.getSkill(Skills.Barbarian.Battle_Orders, 1) * 10 + (me.getSkill(Skills.Barbarian.Shout, 0) + me.getSkill(Skills.Barbarian.Battle_Command, 0)) * 5) * 1000; + this.BOTick = getTickCount(); + this.weaponSwitch(Math.abs(this.haveCTA - 1)); return true; @@ -61,41 +73,111 @@ var Precast = new function () { return false; }; + this.getBetterSlot = function (skillId) { + var item, + sumCurr = 0, + sumSwap = 0; + + switch (skillId) { + case Skills.Paladin.Holy_Shield: // Holy Shield + sumCurr = 0; + sumSwap = 0; + item = me.getItem(); + + if (item) { + do { + if (item.bodylocation === ItemBodyLocation.RIGHT_ARM || item.bodylocation === ItemBodyLocation.LEFT_ARM) { + sumCurr += (item.getStat(Stats.item_allskills) + item.getStat(Stats.item_addclassskills, BaseStat.skills) + item.getStat(Stats.item_addskill_tab, BaseStat.pettype) + item.getStat(Stats.item_singleskill, skillId) + item.getStat(Stats.item_nonclassskill, skillId)); + } + + if (item.bodylocation === ItemBodyLocation.RIGHT_ARM_SECONDARY || item.bodylocation === ItemBodyLocation.LEFT_ARM_SECONDARY) { + sumSwap += (item.getStat(Stats.item_allskills) + item.getStat(Stats.item_addclassskills, BaseStat.skills) + item.getStat(Stats.item_addskill_tab, BaseStat.pettype) + item.getStat(Stats.item_singleskill, skillId) + item.getStat(Stats.item_nonclassskill, skillId)); + } + } while (item.getNext()); + } + + break; + case Skills.Sorceress.Enchant: // Enchant + sumCurr = 0; + sumSwap = 0; + item = me.getItem(); + + if (item) { + do { + if (item.bodylocation === ItemBodyLocation.RIGHT_ARM || item.bodylocation === ItemBodyLocation.LEFT_ARM) { + sumCurr += (item.getStat(Stats.item_allskills) + item.getStat(Stats.item_addclassskills, BaseStat.monster_or_npc_stats) + item.getStat(Stats.item_addskill_tab, BaseStat.levels) + item.getStat(Stats.item_singleskill, skillId) + item.getStat(Stats.item_nonclassskill, skillId)); + } + + if (item.bodylocation === ItemBodyLocation.RIGHT_ARM_SECONDARY || item.bodylocation === ItemBodyLocation.LEFT_ARM_SECONDARY) { + sumSwap += (item.getStat(Stats.item_allskills) + item.getStat(Stats.item_addclassskills, BaseStat.monster_or_npc_stats) + item.getStat(Stats.item_addskill_tab, BaseStat.levels) + item.getStat(Stats.item_singleskill, skillId) + item.getStat(Stats.item_nonclassskill, skillId)); + } + } while (item.getNext()); + } + + break; + } + + print("ÿc4Precastÿc0: Current " + sumCurr + ", Swap " + sumSwap); + + return sumSwap > sumCurr ? Math.abs(me.weaponswitch - 1) : me.weaponswitch; + }; + + this.precastSkill = function (skillId) { + var swapped, + slot = this.getBetterSlot(skillId); + + if (slot !== me.weaponswitch) { + swapped = true; + } + + this.weaponSwitch(slot); + Skill.cast(skillId, 0); + + if (swapped) { + this.weaponSwitch(Math.abs(slot - 1)); + } + + return true; + }; + this.doPrecast = function (force) { var buffSummons = false; - if (!me.getState(32) || force) { - this.precastCTA(force); - } + // Force BO 15 seconds before it expires + this.precastCTA(!me.getState(States.BATTLEORDERS) || force || (getTickCount() - this.BOTick >= this.BODuration - 15000)); switch (me.classid) { - case 0: // Amazon + case ClassID.Amazon: // Amazon if (Config.SummonValkyrie) { - this.summon(32); // Valkyrie - } + this.summon(Skills.Amazon.Valkyrie); // Valkyrie + } break; - case 1: // Sorceress - if (!me.getState(38) || force) { // ts - Skill.cast(57, 0); // Thunder Storm + case ClassID.Sorceress: // Sorceress + if (!me.getState(States.THUNDERSTORM) || force) { // ts + Skill.cast(Skills.Sorceress.Thunder_Storm, 0); // Thunder Storm } - if (!me.getState(30) || force) { - Skill.cast(58, 0); // Energy Shield + if (!me.getState(States.ENERGYSHIELD) || force) { + Skill.cast(Skills.Sorceress.Energy_Shield, 0); // Energy Shield } - if ((!me.getState(88) && !me.getState(10) && !me.getState(20)) || force) { - if (!Skill.cast(50, 0)) { // Shiver Armor - if (!Skill.cast(60, 0)) { // Chilling Armor - Skill.cast(40, 0); // Frozen Armor + if ((!me.getState(States.SHIVERARMOR) && !me.getState(States.FROZENARMOR) && !me.getState(States.CHILLINGARMOR)) || force) { + if (!Skill.cast(Skills.Sorceress.Shiver_Armor, 0)) { // Shiver Armor + if (!Skill.cast(Skills.Sorceress.Chilling_Armor, 0)) { // Chilling Armor + Skill.cast(Skills.Sorceress.Frozen_Armor, 0); // Frozen Armor } } } + if (me.getSkill(Skills.Sorceress.Enchant, 0) && (!me.getState(States.ENCHANT) || force)) { + this.enchant(); + } + break; - case 2: // Necromancer - if (!me.getState(14) || force) { - Skill.cast(68, 0); + case ClassID.Necromancer: // Necromancer + if (!me.getState(States.BONEARMOR) || force) { + Skill.cast(Skills.Necromancer.Bone_Armor, 0); } switch (Config.Golem) { @@ -104,41 +186,41 @@ var Precast = new function () { break; case 1: case "Clay": - this.summon(75); + this.summon(Skills.Necromancer.Clay_Golem); break; case 2: case "Blood": - this.summon(85); + this.summon(Skills.Necromancer.BloodGolem); break; case 3: case "Fire": - this.summon(94); + this.summon(Skills.Necromancer.FireGolem); break; } break; - case 3: // Paladin - if (!me.getState(101) || force) { - Skill.cast(117, 0); // Holy Shield + case ClassID.Paladin: // Paladin + if (!me.getState(States.HOLYSHIELD) || force) { + this.precastSkill(Skills.Paladin.Holy_Shield); // Holy Shield } break; - case 4: // Barbarian - if (!me.getState(32) || !me.getState(51) || !me.getState(26) || force) { + case ClassID.Barbarian: // Barbarian - TODO: BO duration + if (!me.getState(States.BATTLEORDERS) || !me.getState(States.BATTLECOMMAND) || !me.getState(States.SHOUT) || force) { if (Config.BOSwitch) { Precast.weaponSwitch(Config.BOSwitch); } - if (!me.getState(51) || force) { - Skill.cast(155, 0); // Battle Command + if (!me.getState(States.BATTLECOMMAND) || force) { + Skill.cast(Skills.Barbarian.Battle_Command, 0); // Battle Command } - - if (!me.getState(32) || force) { - Skill.cast(149, 0); // Battle Orders + + if (!me.getState(States.BATTLEORDERS) || force) { + Skill.cast(Skills.Barbarian.Battle_Orders, 0); // Battle Orders } - - if (!me.getState(26) || force) { - Skill.cast(138, 0); // Shout + + if (!me.getState(States.SHOUT) || force) { + Skill.cast(Skills.Barbarian.Shout, 0); // Shout } if (Config.BOSwitch) { @@ -147,29 +229,29 @@ var Precast = new function () { } break; - case 5: // Druid - if (!me.getState(151) || force) { - Skill.cast(235, 0); // Cyclone Armor + case ClassID.Druid: // Druid + if (!me.getState(States.CYCLONEARMOR) || force) { + Skill.cast(Skills.Druid.Cyclone_Armor, 0); // Cyclone Armor } - if (Config.SummonRaven) { - this.summon(221); // Raven + if (Config.SummonRaven) { + this.summon(Skills.Druid.Raven); // Raven } switch (Config.SummonAnimal) { case 1: case "Spirit Wolf": - buffSummons = this.summon(227) || buffSummons; // Summon Spirit Wolf + buffSummons = this.summon(Skills.Druid.Summon_Spirit_Wolf) || buffSummons; // Summon Spirit Wolf break; case 2: case "Dire Wolf": - buffSummons = this.summon(237) || buffSummons; // Summon Dire Wolf + buffSummons = this.summon(Skills.Druid.Summon_Fenris) || buffSummons; // Summon Dire Wolf break; case 3: case "Grizzly": - buffSummons = this.summon(247) || buffSummons; // Summon Grizzly + buffSummons = this.summon(Skills.Druid.Summon_Grizzly) || buffSummons; // Summon Grizzly break; } @@ -177,17 +259,17 @@ var Precast = new function () { switch (Config.SummonVine) { case 1: case "Poison Creeper": - buffSummons = this.summon(222) || buffSummons; // Poison Creeper + buffSummons = this.summon(Skills.Druid.Plague_Poppy) || buffSummons; // Poison Creeper break; case 2: case "Carrion Vine": - buffSummons = this.summon(231) || buffSummons; // Carrion Vine + buffSummons = this.summon(Skills.Druid.Cycle_of_Life) || buffSummons; // Carrion Vine break; case 3: case "Solar Creeper": - buffSummons = this.summon(241) || buffSummons; // Solar Creeper + buffSummons = this.summon(Skills.Druid.Vines) || buffSummons; // Solar Creeper break; } @@ -195,23 +277,23 @@ var Precast = new function () { switch (Config.SummonSpirit) { case 1: case "Oak Sage": - buffSummons = this.summon(226) || buffSummons; // Oak Sage + buffSummons = this.summon(Skills.Druid.Oak_Sage) || buffSummons; // Oak Sage break; case 2: case "Heart of Wolverine": - buffSummons = this.summon(236) || buffSummons; // Heart of Wolverine + buffSummons = this.summon(Skills.Druid.Heart_of_Wolverine) || buffSummons; // Heart of Wolverine break; case 3: - case "Solar Creeper": - buffSummons = this.summon(241) || buffSummons; // Solar Creeper + case "Spirit of Barbs": + buffSummons = this.summon(Skills.Druid.Spirit_of_Barbs) || buffSummons; // Spirit of Barbs break; } - if (!me.getState(144) || force) { - Skill.cast(250, 0); // Hurricane + if (!me.getState(States.HURRICANE) || force) { + Skill.cast(Skills.Druid.Hurricane, 0); // Hurricane } if (buffSummons) { @@ -219,31 +301,31 @@ var Precast = new function () { } break; - case 6: // Assassin - if (Config.UseFade && (!me.getState(159) || force)) { - Skill.cast(267, 0); // Fade + case ClassID.Assassin: // Assassin + if (Config.UseFade && (!me.getState(States.FADE) || force)) { + Skill.cast(Skills.Assassin.Fade, 0); // Fade } - if (Config.UseVenom && (!me.getState(31) || force)) { - Skill.cast(278, 0); // Venom + if (Config.UseVenom && (!me.getState(States.VENOMCLAWS) || force)) { + Skill.cast(Skills.Assassin.Venom, 0); // Venom } - if (!me.getState(158) || force) { - Skill.cast(277, 0); // Blade Shield + if (!me.getState(States.BLADESHIELD) || force) { + Skill.cast(Skills.Assassin.Blade_Shield, 0); // Blade Shield } - if (!Config.UseFade && Config.UseBoS && (!me.getState(157) || force)) { - Skill.cast(258, 0); // Burst of Speed + if (!Config.UseFade && Config.UseBoS && (!me.getState(States.QUICKNESS) || force)) { + Skill.cast(Skills.Assassin.Quickness, 0); // Burst of Speed } switch (Config.SummonShadow) { case 1: case "Warrior": - this.summon(268); // Shadow Warrior + this.summon(Skills.Assassin.Shadow_Warrior); // Shadow Warrior break; case 2: case "Master": - this.summon(279); // Shadow Master + this.summon(Skills.Assassin.Shadow_Master); // Shadow Master break; } @@ -255,20 +337,20 @@ var Precast = new function () { var item; if (this.haveCTA < 0) { - item = me.getItem(-1, 1); + item = me.getItem(-1, ItemModes.Item_equipped_self_or_merc); if (item) { MainLoop: do { if (item.getPrefix(20519)) { // Call to Arms switch (item.bodylocation) { - case 4: - case 5: + case ItemBodyLocation.RIGHT_ARM: + case ItemBodyLocation.LEFT_ARM: this.haveCTA = me.weaponswitch; break MainLoop; - case 11: - case 12: + case ItemBodyLocation.RIGHT_ARM_SECONDARY: + case ItemBodyLocation.LEFT_ARM_SECONDARY: this.haveCTA = Math.abs(me.weaponswitch - 1); break MainLoop; @@ -294,49 +376,49 @@ MainLoop: count = 1; switch (skillId) { - case 32: // Valkyrie + case Skills.Amazon.Valkyrie: // Valkyrie minion = 2; break; - case 75: // Clay Golem - case 85: // Blood Golem - case 94: // Fire Golem + case Skills.Necromancer.Clay_Golem: // Clay Golem + case Skills.Necromancer.BloodGolem: // Blood Golem + case Skills.Necromancer.FireGolem: // Fire Golem minion = 3; break; - case 221: // Raven + case Skills.Druid.Raven: // Raven minion = 10; - count = Math.min(me.getSkill(221, 1), 5); + count = Math.min(me.getSkill(Skills.Druid.Raven, 1), 5); break; - case 226: // Oak Sage - case 236: // Heart of Wolverine - case 246: // Spirit of Barbs + case Skills.Druid.Oak_Sage: // Oak Sage + case Skills.Druid.Heart_of_Wolverine: // Heart of Wolverine + case Skills.Druid.Spirit_of_Barbs: // Spirit of Barbs minion = 13; break; - case 222: // Poison Creeper - case 231: // Carrion Vine - case 241: // Solar Creeper + case Skills.Druid.Plague_Poppy: // Poison Creeper + case Skills.Druid.Cycle_of_Life: // Carrion Vine + case Skills.Druid.Vines: // Solar Creeper minion = 14; break; - case 227: // Spirit Wolf + case Skills.Druid.Summon_Spirit_Wolf: // Spirit Wolf minion = 11; - count = Math.min(me.getSkill(227, 1), 5); + count = Math.min(me.getSkill(Skills.Druid.Summon_Spirit_Wolf, 1), 5); break; - case 237: // Dire Wolf + case Skills.Druid.Summon_Fenris: // Dire Wolf minion = 12; - count = Math.min(me.getSkill(237, 1), 3); + count = Math.min(me.getSkill(Skills.Druid.Summon_Fenris, 1), 3); break; - case 247: // Grizzly + case Skills.Druid.Summon_Grizzly: // Grizzly minion = 15; break; - case 268: // Shadow Warrior - case 279: // Shadow Master + case Skills.Assassin.Shadow_Warrior: // Shadow Warrior + case Skills.Assassin.Shadow_Master: // Shadow Master minion = 16; break; @@ -351,4 +433,45 @@ MainLoop: return !!rv; }; + + this.enchant = function () { + var unit, swapped, + slot = this.getBetterSlot(Skills.Sorceress.Enchant), + chanted = []; + + if (slot !== me.weaponswitch) { + swapped = true; + } + + this.weaponSwitch(slot); + + // Player + unit = getUnit(UnitType.Player); + + if (unit) { + do { + if (!unit.dead && Misc.inMyParty(unit.name) && getDistance(me, unit) <= 40) { + Skill.cast(Skills.Sorceress.Enchant, 0, unit); + chanted.push(unit.name); + } + } while (unit.getNext()); + } + + // Minion + unit = getUnit(UnitType.NPC); + + if (unit) { + do { + if (unit.getParent() && chanted.indexOf(unit.getParent().name) > -1 && getDistance(me, unit) <= 40) { + Skill.cast(Skills.Sorceress.Enchant, 0, unit); + } + } 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 980f8645e..273f98daf 100644 --- a/d2bs/kolbot/libs/common/Prototypes.js +++ b/d2bs/kolbot/libs/common/Prototypes.js @@ -4,6 +4,34 @@ * @desc various 'Unit' and 'me' prototypes */ +// Shuffle Array +// http://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array-in-javascript +Array.prototype.shuffle = function () { + var temp, index, + counter = this.length; + + // While there are elements in the array + while (counter > 0) { + // Pick a random index + index = Math.floor(Math.random() * counter); + + // Decrease counter by 1 + counter -= 1; + + // And swap the last element with it + temp = this[counter]; + this[counter] = this[index]; + this[index] = temp; + } + + return this; +}; + +// Trim String +String.prototype.trim = function () { + return this.replace(/^\s+|\s+$/g, ""); +}; + // Check if unit is idle Unit.prototype.__defineGetter__("idle", function () { @@ -11,9 +39,26 @@ Unit.prototype.__defineGetter__("idle", throw new Error("Unit.idle: Must be used with player units."); } - return (me.mode === 1 || me.mode === 5); - } - ); + return (this.mode === PlayerModes.Neutral || this.mode === PlayerModes.Town_Neutral || this.mode === PlayerModes.Dead); // Dead is pretty idle too + }); + +Unit.prototype.__defineGetter__("gold", + function () { + return this.getStat(Stats.gold) + this.getStat(Stats.goldbank); + }); + +// Death check +Unit.prototype.__defineGetter__("dead", + function () { + switch (this.type) { + case UnitType.Player: // Player + return this.mode === PlayerModes.Death || this.mode === PlayerModes.Dead; + case UnitType.NPC: // Monster + return this.mode === NPCModes.death || this.mode === NPCModes.dead; + default: + return false; + } + }); // Check if unit is in town Unit.prototype.__defineGetter__("inTown", @@ -22,16 +67,14 @@ Unit.prototype.__defineGetter__("inTown", throw new Error("Unit.inTown: Must be used with player units."); } - return [1, 40, 75, 103, 109].indexOf(this.area) > -1; - } - ); + return [Areas.Act1.Rogue_Encampment, Areas.Act2.Lut_Gholein, Areas.Act3.Kurast_Docktown, Areas.Act4.The_Pandemonium_Fortress, Areas.Act5.Harrogath].indexOf(this.area) > -1; + }); // Check if party unit is in town Party.prototype.__defineGetter__("inTown", function () { - return [1, 40, 75, 103, 109].indexOf(this.area) > -1; - } - ); + return [Areas.Act1.Rogue_Encampment, Areas.Act2.Lut_Gholein, Areas.Act3.Kurast_Docktown, Areas.Act4.The_Pandemonium_Fortress, Areas.Act5.Harrogath].indexOf(this.area) > -1; + }); Unit.prototype.__defineGetter__("attacking", function () { @@ -39,38 +82,54 @@ 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 [PlayerModes.Attack1, PlayerModes.Attack2, PlayerModes.Cast, PlayerModes.Throw, PlayerModes.Kick, PlayerModes.Skill1, + PlayerModes.Skill2, PlayerModes.Skill3, PlayerModes.Skill4, PlayerModes.Sequence].indexOf(this.mode) > -1; + }); // Open NPC menu -Unit.prototype.openMenu = function () { +Unit.prototype.openMenu = function (addDelay) { + if (Config.PacketShopping) { + return Packet.openMenu(this); + } + if (this.type !== 1) { throw new Error("Unit.openMenu: Must be used on NPCs."); } - if (getUIFlag(0x08)) { + if (addDelay === undefined) { + addDelay = 0; + } + + if (getUIFlag(UIFlags.npc_menu)) { return true; } var i, j; - for (i = 0; i < 3; i += 1) { - if (getDistance(me, this) > 3) { + for (i = 0; i < 5; i += 1) { + if (getDistance(me, this) > 4) { Pather.moveToUnit(this); } - this.interact(); + if (i > 0) { + Packet.flash(me.gid); + // delay? + } + + if (!getUIFlag(UIFlags.npc_menu)) { + delay(100); + this.interact(); + } for (j = 0; j < 40; j += 1) { - if (j % 8 === 0) { + if (j > 0 && j % 10 === 0 && !getUIFlag(UIFlags.npc_menu)) { me.cancel(); - delay(300); + delay(400); this.interact(); } - if (getUIFlag(0x08)) { - delay(600); + if (getUIFlag(UIFlags.npc_menu)) { + delay(Math.max(700 + me.ping, 500 + me.ping * 2 + addDelay * 500)); return true; } @@ -82,13 +141,17 @@ Unit.prototype.openMenu = function () { return false; }; -// mode = "Gamble", "Repair" or "Trade" +// mode = "Gamble", "Repair" or "Shop" Unit.prototype.startTrade = function (mode) { + if (Config.PacketShopping) { + return Packet.startTrade(this, mode); + } + if (this.type !== 1) { throw new Error("Unit.startTrade: Must be used on NPCs."); } - if (getUIFlag(0x0C)) { + if (getUIFlag(UIFlags.Shop_open_at_NPC)) { return true; } @@ -96,55 +159,64 @@ Unit.prototype.startTrade = function (mode) { menuId = mode === "Gamble" ? 0x0D46 : mode === "Repair" ? 0x0D06 : 0x0D44; for (i = 0; i < 3; i += 1) { - if (!this.openMenu()) { - continue; - } + if (this.openMenu(i)) { // Incremental delay on retries + Misc.useMenu(menuId); - delay(10); - this.useMenu(menuId); - delay(10); + tick = getTickCount(); - tick = getTickCount(); + while (getTickCount() - tick < 1000) { + if (getUIFlag(UIFlags.Shop_open_at_NPC) && this.itemcount > 0) { + delay(200); - while (getTickCount() - tick < 1000) { - if (getUIFlag(0x0C) && this.itemcount > 0) { - delay(200); + return true; + } - return true; + delay(25); } - delay(25); + me.cancel(); } - - me.cancel(); } return false; }; -Unit.prototype.buy = function (shiftBuy) { - if (this.type !== 4) { // Check if it's an item we want to buy +Unit.prototype.buy = function (shiftBuy, gamble) { + if (Config.PacketShopping) { + return Packet.buyItem(this, shiftBuy, gamble); + } + + if (this.type !== UnitType.Item) { // Check if it's an item we want to buy throw new Error("Unit.buy: Must be used on items."); } - if (!getUIFlag(0xC) || this.getParent().gid !== getInteractedNPC().gid) { // Check if it's an item belonging to a NPC + if (!getUIFlag(UIFlags.Shop_open_at_NPC) || (this.getParent() && this.getParent().gid !== getInteractedNPC().gid)) { // Check if it's an item belonging to a NPC throw new Error("Unit.buy: Must be used in shops."); } - if (me.getStat(14) + me.getStat(15) < this.getItemCost(0)) { // Can we afford the item? + if (me.getStat(Stats.gold) + me.getStat(Stats.goldbank) < this.getItemCost(0)) { // Can we afford the item? return false; } var i, tick, - gold = me.getStat(14) + me.getStat(15); + oldGold = me.getStat(Stats.gold) + me.getStat(Stats.goldbank), + itemCount = me.itemcount; for (i = 0; i < 3; i += 1) { + //print("BUY " + this.name + " " + i); + this.shop(shiftBuy ? 6 : 2); tick = getTickCount(); - while (getTickCount() - tick < 2000) { - if (me.getStat(14) + me.getStat(15) !== gold) { + while (getTickCount() - tick < Math.max(2000, me.ping * 2 + 500)) { + if (shiftBuy && me.getStat(Stats.gold) + me.getStat(Stats.goldbank) < oldGold) { + delay(500); + + return true; + } + + if (itemCount !== me.itemcount) { delay(500); return true; @@ -157,17 +229,37 @@ Unit.prototype.buy = function (shiftBuy) { return false; }; +// Item owner name +Unit.prototype.__defineGetter__("parentName", + function () { + if (this.type !== UnitType.Item) { + throw new Error("Unit.parentName: Must be used with item units."); + } + + var parent = this.getParent(); + + if (parent) { + return parent.name; + } + + return false; + }); + // You MUST use a delay after Unit.sell() if using custom scripts. delay(500) works best, dynamic delay is used when identifying/selling (500 - item id time) Unit.prototype.sell = function () { - if (this.type !== 4) { // Check if it's an item we want to buy + if (Config.PacketShopping) { + return Packet.sellItem(this); + } + + if (this.type !== UnitType.Item) { // Check if it's an item we want to buy throw new Error("Unit.sell: Must be used on items."); } - if (!getUIFlag(0xC)) { // Check if it's an item belonging to a NPC + if (!getUIFlag(UIFlags.Shop_open_at_NPC)) { // Check if it's an item belonging to a NPC throw new Error("Unit.sell: Must be used in shops."); } - var i, tick, timer, + var i, tick, itemCount = me.itemcount; for (i = 0; i < 5; i += 1) { @@ -186,23 +278,29 @@ Unit.prototype.sell = function () { } } - //D2Bot.printToConsole("Unit.sell: Sell item failed.;1"); - return false; }; Unit.prototype.toCursor = function () { - if (this.type !== 4) { + if (this.type !== UnitType.Item) { throw new Error("Unit.toCursor: Must be used with items."); } + if (me.itemoncursor && this.mode === ItemModes.Item_on_cursor) { + 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 fro example) - } else { - clickItem(0, this); + try { + if (this.mode === ItemModes.Item_equipped_self_or_merc) { + clickItem(ClickType.Left_Click, this.bodylocation); // fix for equipped items (cubing viper staff for example) + } else { + clickItem(ClickType.Left_Click, this); + } + } catch (e) { + return false; } tick = getTickCount(); @@ -222,7 +320,7 @@ Unit.prototype.toCursor = function () { }; Unit.prototype.drop = function () { - if (this.type !== 4) { + if (this.type !== UnitType.Item) { throw new Error("Unit.drop: Must be used with items."); } @@ -253,67 +351,47 @@ Unit.prototype.drop = function () { return false; }; -me.findItem = function (id, mode, loc) { - if (this.type > 1) { - throw new Error("Unit.findItem: Must be used on PCs or NPCs."); - } - - switch (arguments.length) { - case 0: +me.findItem = function (id, mode, loc, quality) { + if (id === undefined) { id = -1; - mode = -1; - loc = false; + } - break; - case 1: + if (mode === undefined) { mode = -1; - loc = false; - - break; - case 2: - loc = false; - - break; } - var item = this.getItem(id, mode); + if (loc === undefined) { + loc = -1; + } - 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) { - switch (arguments.length) { - case 0: + if (id === undefined) { id = -1; - mode = -1; - loc = false; + } - break; - case 1: + if (mode === undefined) { mode = -1; - loc = false; + } - break; - case 2: + if (loc === undefined) { loc = false; - - break; } var list = [], @@ -333,43 +411,617 @@ me.findItems = function (id, mode, loc) { } } while (item.getNext()); - if (!list.length) { - return false; - } - return list; }; Unit.prototype.getPrefix = function (id) { - if (typeof this.prefixnum === "number") { - return this.prefixnum === id; - } + var i; + + switch (typeof id) { + case "number": + if (typeof this.prefixnums !== "object") { + return this.prefixnum === id; + } + + for (i = 0; i < this.prefixnums.length; i += 1) { + if (id === this.prefixnums[i]) { + return true; + } + } - var i, - prefixList = this.prefixnum; + break; + case "string": + if (typeof this.prefixes !== "object") { + return this.prefix.replace(/\s+/g, "").toLowerCase() === id.replace(/\s+/g, "").toLowerCase(); + } - for (i = 0; i < prefixList.length; i += 1) { - if (id === prefixList[i]) { - return true; + for (i = 0; i < this.prefixes.length; i += 1) { + if (id.replace(/\s+/g, "").toLowerCase() === this.prefixes[i].replace(/\s+/g, "").toLowerCase()) { + return true; + } } + + break; } return false; }; Unit.prototype.getSuffix = function (id) { - if (typeof this.suffixnum === "number") { - return this.suffixnum === id; - } + var i; - var i, - suffixList = this.suffixnum; + switch (typeof id) { + case "number": + if (typeof this.suffixnums !== "object") { + return this.suffixnum === id; + } - for (i = 0; i < suffixList.length; i += 1) { - if (id === suffixList[i]) { - return true; + for (i = 0; i < this.suffixnums.length; i += 1) { + if (id === this.suffixnums[i]) { + return true; + } } + + break; + case "string": + if (typeof this.suffixes !== "object") { + return this.suffix.replace(/\s+/g, "").toLowerCase() === id.replace(/\s+/g, "").toLowerCase(); + } + + for (i = 0; i < this.suffixes.length; i += 1) { + if (id.replace(/\s+/g, "").toLowerCase() === this.suffixes[i].replace(/\s+/g, "").toLowerCase()) { + return true; + } + } + + break; } return false; +}; + +Unit.prototype.__defineGetter__("dexreq", + function () { + var finalReq, + ethereal = this.getFlag(ItemFlags.isEthereal), + reqModifier = this.getStat(Stats.item_req_percent), + baseReq = getBaseStat("items", this.classid, "reqdex"); + + finalReq = baseReq + Math.floor(baseReq * reqModifier / 100); + + if (ethereal) { + finalReq -= 10; + } + + return Math.max(finalReq, 0); + }); + +Unit.prototype.__defineGetter__("strreq", + function () { + var finalReq, + ethereal = this.getFlag(ItemFlags.isEthereal), + reqModifier = this.getStat(Stats.item_req_percent), + baseReq = getBaseStat("items", this.classid, "reqstr"); + + finalReq = baseReq + Math.floor(baseReq * reqModifier / 100); + + if (ethereal) { + finalReq -= 10; + } + + return Math.max(finalReq, 0); + }); + +Unit.prototype.__defineGetter__('itemclass', + function () { + if (getBaseStat(BaseStat.items, this.classid, 'code') === undefined) { + return 0; + } + + if (getBaseStat(BaseStat.items, this.classid, 'code') === getBaseStat(BaseStat.items, this.classid, 'ultracode')) { + return 2; + } + + if (getBaseStat(BaseStat.items, this.classid, 'code') === getBaseStat(BaseStat.items, this.classid, 'ubercode')) { + return 1; + } + + return 0; + }); + +Unit.prototype.getStatEx = function (id, subid) { + var i, temp, rval, regex; + + switch (id) { + case Stats.toblock: // toblock + switch (this.classid) { + case ItemClassIds.Buckler: // buckler + return this.getStat(Stats.toblock); + case ItemClassIds.Preserved_Head: // preserved + case ItemClassIds.Mummified_Trophy: // mummified + case ItemClassIds.Minion_Skull: // minion + return this.getStat(Stats.toblock) - 3; + case ItemClassIds.Small_Shield: // small + case ItemClassIds.Zombie_Head: // zombie + case ItemClassIds.Fetish_Trophy: // fetish + case ItemClassIds.Hellspawn_Skull: // hellspawn + return this.getStat(Stats.toblock) - 5; + case ItemClassIds.Kite_Shield: // kite + case ItemClassIds.Unraveller_Head: // unraveller + case ItemClassIds.Sexton_Trophy: // sexton + case ItemClassIds.Overseer_Skull: // overseer + return this.getStat(Stats.toblock) - 8; + case ItemClassIds.Spiked_Shield: // spiked + case ItemClassIds.Defender: // deefender + case ItemClassIds.Gargoyle_Head: // gargoyle + case ItemClassIds.Cantor_Trophy: // cantor + case ItemClassIds.Succubus_Skull: // succubus + case ItemClassIds.Targe: // targe + case ItemClassIds.Akaran_Targe: // akaran t + return this.getStat(Stats.toblock) - 10; + case ItemClassIds.Large_Shield: // large + case ItemClassIds.Round_Shield: // round + case ItemClassIds.Demon_Head: // demon + case ItemClassIds.Hierophant_Trophy: // hierophant + case ItemClassIds.Bloodlord_Skull: // bloodlord + return this.getStat(Stats.toblock) - 12; + case ItemClassIds.Scutum: // scutum + return this.getStat(Stats.toblock) - 14; + case ItemClassIds.Rondache: // rondache + case ItemClassIds.Akaran_Rondache: // akaran r + return this.getStat(Stats.toblock) - 15; + case ItemClassIds.Gothic_Shield: // goth + case ItemClassIds.Ancient_Shield: // ancient + return this.getStat(Stats.toblock) - 16; + case ItemClassIds.Barbed_Shield: // barbed + return this.getStat(Stats.toblock) - 17; + case ItemClassIds.Dragon_Shield: // dragon + return this.getStat(Stats.toblock) - 18; + case ItemClassIds.Vortex_Shield: // vortex + return this.getStat(Stats.toblock) - 19; + case ItemClassIds.Bone_Shield: // bone + case ItemClassIds.Grim_Shield: // grim + case ItemClassIds.Luna: // luna + case ItemClassIds.Blade_Barrier: // blade barr + case ItemClassIds.Troll_Nest: // troll + case ItemClassIds.Heraldic_Shield: // heraldic + case ItemClassIds.Protector_Shield: // protector + return this.getStat(Stats.toblock) - 20; + case ItemClassIds.Heater: // heater + case ItemClassIds.Monarch: // monarch + case ItemClassIds.Aerin_Shield: // aerin + case ItemClassIds.Gilded_Shield: // gilded + case ItemClassIds.Zakarum_Shield: // zakarum + return this.getStat(Stats.toblock) - 22; + case ItemClassIds.Tower_Shield: // tower + case ItemClassIds.Pavise: // pavise + case ItemClassIds.Hyperion: // hyperion + case ItemClassIds.Aegis: // aegis + case ItemClassIds.Ward: // ward + return this.getStat(Stats.toblock) - 24; + case ItemClassIds.Crown_Shield: // crown + case ItemClassIds.Royal_Shield: // royal + case ItemClassIds.Kurast_Shield: // kurast + return this.getStat(Stats.toblock) - 25; + case ItemClassIds.Sacred_Rondache: // sacred r + return this.getStat(Stats.toblock) - 28; + case ItemClassIds.Sacred_Targe: // sacred t + return this.getStat(Stats.toblock) - 30; + } + + break; + case Stats.mindamage: // plusmindamage + case Stats.maxdamage: // plusmaxdamage + if (subid === 1) { + temp = this.getStat(-1); + rval = 0; + + for (i = 0; i < temp.length; i += 1) { + switch (temp[i][0]) { + case id: // plus one handed dmg + case id + 2: // plus two handed dmg + // There are 2 occurrences of min/max if the item has +damage. Total damage is the sum of both. + // First occurrence is +damage, second is base item damage. + + if (rval) { // First occurence stored, return if the second one exists + return rval; + } + + if (this.getStat(temp[i][0]) > 0 && this.getStat(temp[i][0]) > temp[i][2]) { + rval = temp[i][2]; // Store the potential +dmg value + } + + break; + } + } + + return 0; + } + + break; + case Stats.armorclass: // plusdefense + if (subid === 0) { + if ([0, 1].indexOf(this.mode) < 0) { + break; + } + + switch (this.itemType) { + case NTItemTypes.jewel: // jewel + case NTItemTypes.smallcharm: // charms + case NTItemTypes.mediumcharm: + case NTItemTypes.largecharm: + // defense is the same as plusdefense for these items + return this.getStat(Stats.armorclass); + } + + if (!this.desc) { + this.desc = this.description; + } + + temp = this.desc.split("\n"); + regex = new RegExp("\\+\\d+ " + getLocaleString(3481)); + + for (i = 0; i < temp.length; i += 1) { + if (temp[i].match(regex, "i")) { + return parseInt(temp[i].replace(/ÿc[0-9!"+<;.*]/, ""), 10); + } + } + + return 0; + } + + break; + case Stats.poisonmindam: + if (subid === 1) { + return Math.round(this.getStat(Stats.poisonmindam) * this.getStat(Stats.poisonlength) / 256); + } + + break; + case Stats.item_addclassskills: // itemaddclassskills + if (subid === undefined) { + for (i = 0; i < 7; i += 1) { + if (this.getStat(Stats.item_addclassskills, i)) { + return this.getStat(Stats.item_addclassskills, i); + } + } + + return 0; + } + + break; + case Stats.item_addskill_tab: // itemaddskilltab + if (subid === undefined) { + temp = [0, 1, 2, 8, 9, 10, 16, 17, 18, 24, 25, 26, 32, 33, 34, 40, 41, 42, 48, 49, 50]; + + for (i = 0; i < temp.length; i += 1) { + if (this.getStat(Stats.item_addskill_tab, temp[i])) { + return this.getStat(Stats.item_addskill_tab, temp[i]); + } + } + + return 0; + } + + break; + case Stats.item_skillonattack: // itemskillonattack + case Stats.item_skillonhit: // itemskillonhit + case Stats.item_charged_skill: // itemchargedskill + if (subid === undefined) { + temp = this.getStat(-2); + + if (temp.hasOwnProperty(id)) { + if (temp[id] instanceof Array) { + for (i = 0; i < temp[id].length; i += 1) { + if (temp[id][i] !== undefined) { + return temp[id][i].skill; + } + } + } else { + return temp[id].skill; + } + } + + return 0; + } + + break; + } + + if (this.getFlag(ItemFlags.isRuneword)) { // Runeword + switch (id) { + case 16: // enhanceddefense + if ([0, 1].indexOf(this.mode) < 0) { + break; + } + + if (!this.desc) { + this.desc = this.description; + } + + temp = this.desc.split("\n"); + + for (i = 0; i < temp.length; i += 1) { + if (temp[i].match(getLocaleString(3520), "i")) { + return parseInt(temp[i].replace(/ÿc[0-9!"+<;.*]/, ""), 10); + } + } + + return 0; + case 18: // enhanceddamage + if ([0, 1].indexOf(this.mode) < 0) { + break; + } + + if (!this.desc) { + this.desc = this.description; + } + + temp = this.desc.split("\n"); + + for (i = 0; i < temp.length; i += 1) { + if (temp[i].match(getLocaleString(10038), "i")) { + return parseInt(temp[i].replace(/ÿc[0-9!"+<;.*]/, ""), 10); + } + } + + return 0; + } + } + + if (subid === undefined) { + return this.getStat(id); + } + + return this.getStat(id, subid); +}; + +/* + _NTIPAliasColor["black"] = 3; + _NTIPAliasColor["lightblue"] = 4; + _NTIPAliasColor["darkblue"] = 5; + _NTIPAliasColor["crystalblue"] = 6; + _NTIPAliasColor["lightred"] = 7; + _NTIPAliasColor["darkred"] = 8; + _NTIPAliasColor["crystalred"] = 9; + _NTIPAliasColor["darkgreen"] = 11; + _NTIPAliasColor["crystalgreen"] = 12; + _NTIPAliasColor["lightyellow"] = 13; + _NTIPAliasColor["darkyellow"] = 14; + _NTIPAliasColor["lightgold"] = 15; + _NTIPAliasColor["darkgold"] = 16; + _NTIPAliasColor["lightpurple"] = 17; + _NTIPAliasColor["orange"] = 19; + _NTIPAliasColor["white"] = 20; +*/ + +Unit.prototype.getColor = function () { + var i, colors, + Color = { + black: 3, + lightblue: 4, + darkblue: 5, + crystalblue: 6, + lightred: 7, + darkred: 8, + crystalred: 9, + darkgreen: 11, + crystalgreen: 12, + lightyellow: 13, + darkyellow: 14, + lightgold: 15, + darkgold: 16, + lightpurple: 17, + orange: 19, + white: 20 + }; + + // check type + + if ([NTItemTypes.shield, NTItemTypes.armor, NTItemTypes.boots, NTItemTypes.gloves, NTItemTypes.belt, + NTItemTypes.scepter, NTItemTypes.wand, NTItemTypes.staff, NTItemTypes.bow, NTItemTypes.axe, + NTItemTypes.club, NTItemTypes.sword, NTItemTypes.hammer, NTItemTypes.knife, NTItemTypes.spear, + NTItemTypes.polearm, NTItemTypes.crossbow, NTItemTypes.mace, NTItemTypes.helm, NTItemTypes.throwingknife, + NTItemTypes.throwingaxe, NTItemTypes.javelin, NTItemTypes.handtohand, NTItemTypes.orb, NTItemTypes.primalhelm, + NTItemTypes.pelt, NTItemTypes.amazonbow, NTItemTypes.amazonspear, NTItemTypes.amazonjavelin, NTItemTypes.assassinclaw].indexOf(this.itemType) === -1) { + return -1; + } + + // check quality + if ([ItemQuality.Magic, ItemQuality.Set, ItemQuality.Rare, ItemQuality.Unique].indexOf(this.quality) === -1) { + return -1; + } + + if (this.quality === ItemQuality.Magic || this.quality === ItemQuality.Rare) { + colors = { + "Screaming": Color.orange, + "Howling": Color.orange, + "Wailing": Color.orange, + "Sapphire": Color.lightblue, + "Snowy": Color.lightblue, + "Shivering": Color.lightblue, + "Boreal": Color.lightblue, + "Hibernal": Color.lightblue, + "Ruby": Color.lightred, + "Amber": Color.lightyellow, + "Static": Color.lightyellow, + "Glowing": Color.lightyellow, + "Buzzing": Color.lightyellow, + "Arcing": Color.lightyellow, + "Shocking": Color.lightyellow, + "Emerald": Color.crystalgreen, + "Saintly": Color.darkgold, + "Holy": Color.darkgold, + "Godly": Color.darkgold, + "Visionary": Color.white, + "Mnemonic": Color.crystalblue, + "Bowyer's": Color.lightgold, + "Gymnastic": Color.lightgold, + "Spearmaiden's": Color.lightgold, + "Archer's": Color.lightgold, + "Athlete's": Color.lightgold, + "Lancer's": Color.lightgold, + "Charged": Color.lightgold, + "Blazing": Color.lightgold, + "Freezing": Color.lightgold, + "Glacial": Color.lightgold, + "Powered": Color.lightgold, + "Volcanic": Color.lightgold, + "Blighting": Color.lightgold, + "Noxious": Color.lightgold, + "Mojo": Color.lightgold, + "Cursing": Color.lightgold, + "Venomous": Color.lightgold, + "Golemlord's": Color.lightgold, + "Warden's": Color.lightgold, + "Hawk Branded": Color.lightgold, + "Commander's": Color.lightgold, + "Marshal's": Color.lightgold, + "Rose Branded": Color.lightgold, + "Guardian's": Color.lightgold, + "Veteran's": Color.lightgold, + "Resonant": Color.lightgold, + "Raging": Color.lightgold, + "Echoing": Color.lightgold, + "Furious": Color.lightgold, + "Master's": Color.lightgold, // there's 2x masters... + "Caretaker's": Color.lightgold, + "Terrene": Color.lightgold, + "Feral": Color.lightgold, + "Gaean": Color.lightgold, + "Communal": Color.lightgold, + "Keeper's": Color.lightgold, + "Sensei's": Color.lightgold, + "Trickster's": Color.lightgold, + "Psychic": Color.lightgold, + "Kenshi's": Color.lightgold, + "Cunning": Color.lightgold, + "Shadow": Color.lightgold, + "Faithful": Color.white, + "Priest's": Color.crystalgreen, + "Dragon's": Color.crystalblue, + "Vulpine": Color.crystalblue, + "Shimmering": Color.lightpurple, + "Rainbow": Color.lightpurple, + "Scintillating": Color.lightpurple, + "Prismatic": Color.lightpurple, + "Chromatic": Color.lightpurple, + "Hierophant's": Color.crystalgreen, + "Berserker's": Color.crystalgreen, + "Necromancer's": Color.crystalgreen, + "Witch-hunter's": Color.crystalgreen, + "Arch-Angel's": Color.crystalgreen, + "Valkyrie's": Color.crystalgreen, + "Massive": Color.darkgold, + "Savage": Color.darkgold, + "Merciless": Color.darkgold, + "Ferocious": Color.black, + "Grinding": Color.white, + "Cruel": Color.black, + "Gold": Color.lightgold, + "Platinum": Color.lightgold, + "Meteoric": Color.lightgold, + "Strange": Color.lightgold, + "Weird": Color.lightgold, + "Knight's": Color.darkgold, + "Lord's": Color.darkgold, + "Fool's": Color.white, + "King's": Color.darkgold, + //"Master's": Color.darkgold, + "Elysian": Color.darkgold, + "Fiery": Color.darkred, + "Smoldering": Color.darkred, + "Smoking": Color.darkred, + "Flaming": Color.darkred, + "Condensing": Color.darkred, + "Septic": Color.darkgreen, + "Foul": Color.darkgreen, + "Corrosive": Color.darkgreen, + "Toxic": Color.darkgreen, + "Pestilent": Color.darkgreen, + "of Quickness": Color.darkyellow, + "of the Glacier": Color.darkblue, + "of Winter": Color.darkblue, + "of Burning": Color.darkred, + "of Incineration": Color.darkred, + "of Thunder": Color.darkyellow, + "of Storms": Color.darkyellow, + "of Carnage": Color.black, + "of Slaughter": Color.black, + "of Butchery": Color.black, + "of Evisceration": Color.black, + "of Performance": Color.black, + "of Transcendence": Color.black, + "of Pestilence": Color.darkgreen, + "of Anthrax": Color.darkgreen, + "of the Locust": Color.crystalred, + "of the Lamprey": Color.crystalred, + "of the Wraith": Color.crystalred, + "of the Vampire": Color.crystalred, + "of Icebolt": Color.lightblue, + "of Nova": Color.crystalblue, + "of the Mammoth": Color.crystalred, + "of Frost Shield": Color.lightblue, + "of Nova Shield": Color.crystalblue, + "of Wealth": Color.lightgold, + "of Fortune": Color.lightgold, + "of Luck": Color.lightgold, + "of Perfection": Color.darkgold, + "of Regrowth": Color.crystalred, + "of Spikes": Color.orange, + "of Razors": Color.orange, + "of Swords": Color.orange, + "of Stability": Color.darkyellow, + "of the Colosuss": Color.crystalred, + "of the Squid": Color.crystalred, + "of the Whale": Color.crystalred, + "of Defiance": Color.darkred, + "of the Titan": Color.darkgold, + "of Atlas": Color.darkgold, + "of Wizardry": Color.darkgold + }; + + switch (this.itemType) { + case NTItemTypes.boots: // boots + colors["of Precision"] = Color.darkgold; + + break; + case NTItemTypes.gloves: // gloves + colors["of Alacrity"] = Color.darkyellow; + colors["of the Leech"] = Color.crystalred; + colors["of the Bat"] = Color.crystalred; + colors["of the Giant"] = Color.darkgold; + + break; + } + } else if (this.quality === ItemQuality.Set) { // Set + if (this.getFlag(ItemFlags.isIdentified)) { + for (i = 0; i < 127; i += 1) { + if (this.fname.split("\n").reverse()[0].indexOf(getLocaleString(getBaseStat(BaseStat.setitems, i, 3))) > -1) { + return getBaseStat(BaseStat.setitems, i, 12) > 20 ? -1 : getBaseStat(BaseStat.setitems, i, 12); + } + } + } else { + return Color.lightyellow; // Unidentified set item + } + } else if (this.quality === ItemQuality.Unique) { // Unique + for (i = 0; i < 401; i += 1) { + if (this.fname.split("\n").reverse()[0].indexOf(getLocaleString(getBaseStat(BaseStat.uniqueitems, i, 2))) > -1) { + return getBaseStat(BaseStat.uniqueitems, i, 13) > 20 ? -1 : getBaseStat(BaseStat.uniqueitems, i, 13); + } + } + } + + for (i = 0; i < this.suffixes.length; i += 1) { + if (colors.hasOwnProperty(this.suffixes[i])) { + return colors[this.suffixes[i]]; + } + } + + for (i = 0; i < this.prefixes.length; i += 1) { + if (colors.hasOwnProperty(this.prefixes[i])) { + return colors[this.prefixes[i]]; + } + } + + return -1; }; \ No newline at end of file diff --git a/d2bs/kolbot/libs/common/Runewords.js b/d2bs/kolbot/libs/common/Runewords.js index f071a31ef..f25293115 100644 --- a/d2bs/kolbot/libs/common/Runewords.js +++ b/d2bs/kolbot/libs/common/Runewords.js @@ -4,91 +4,97 @@ * @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 - Black: [619, 625, 613], // Thul + Io + Nef - Fury: [640, 634, 614], // Jah + Gul + Eth - HolyThunder: [614, 617, 618, 616], // Eth + Ral + Ort + Tal - Honor: [620, 610, 615, 612, 621], // Amn + El + Ith + Tir + Sol - KingsGrace: [620, 617, 619], // Amn + Ral + Thul - Leaf: [612, 617], // Tir + Ral - Lionheart: [624, 626, 628], // Hel + Lum + Fal - Lore: [618, 621], // Ort + Sol - Malice: [615, 610, 614], // Ith + El + Eth - Melody: [622, 627, 613], // Shael + Ko + Nef - Memory: [626, 625, 621, 614], // Lum + Io + Sol + Eth - Nadir: [613, 612], // Nef + Tir - Radiance: [613, 621, 615], // Nef + Sol + Ith - Rhyme: [622, 614], // Shael + Eth - Silence: [623, 611, 624, 633, 612, 635], // Dol + Eld + Hel + Ist + Tir + Vex - Smoke: [613, 626], // Nef + Lum - Stealth: [616, 614], // Tal + Eth - Steel: [612, 610], // Tir + El - Strength: [620, 612], // Amn + Tir - Venom: [616, 623, 632], // Tal + Dol + Mal - Wealth: [629, 627, 612], // Lem + Ko + Tir - White: [623, 625], // Dol + Io - Zephyr: [618, 614], // Ort + Eth + AncientsPledge: [ItemClassIds.Ral_Rune, ItemClassIds.Ort_Rune, ItemClassIds.Tal_Rune], // Ral + Ort + Tal + Black: [ItemClassIds.Thul_Rune, ItemClassIds.Io_Rune, ItemClassIds.Nef_Rune], // Thul + Io + Nef + Fury: [ItemClassIds.Jah_Rune, ItemClassIds.Gul_Rune, ItemClassIds.Eth_Rune], // Jah + Gul + Eth + HolyThunder: [ItemClassIds.Eth_Rune, ItemClassIds.Ral_Rune, ItemClassIds.Ort_Rune, ItemClassIds.Tal_Rune], // Eth + Ral + Ort + Tal + Honor: [ItemClassIds.Amn_Rune, ItemClassIds.El_Rune, ItemClassIds.Ith_Rune, ItemClassIds.Tir_Rune, ItemClassIds.Sol_Rune], // Amn + El + Ith + Tir + Sol + KingsGrace: [ItemClassIds.Amn_Rune, ItemClassIds.Ral_Rune, ItemClassIds.Thul_Rune], // Amn + Ral + Thul + Leaf: [ItemClassIds.Tir_Rune, ItemClassIds.Ral_Rune], // Tir + Ral + Lionheart: [ItemClassIds.Hel_Rune, ItemClassIds.Lum_Rune, ItemClassIds.Fal_Rune], // Hel + Lum + Fal + Lore: [ItemClassIds.Ort_Rune, ItemClassIds.Sol_Rune], // Ort + Sol + Malice: [ItemClassIds.Ith_Rune, ItemClassIds.El_Rune, ItemClassIds.Eth_Rune], // Ith + El + Eth + Melody: [ItemClassIds.Shael_Rune, ItemClassIds.Ko_Rune, ItemClassIds.Nef_Rune], // Shael + Ko + Nef + Memory: [ItemClassIds.Lum_Rune, ItemClassIds.Io_Rune, ItemClassIds.Sol_Rune, ItemClassIds.Eth_Rune], // Lum + Io + Sol + Eth + Nadir: [ItemClassIds.Nef_Rune, ItemClassIds.Tir_Rune], // Nef + Tir + Radiance: [ItemClassIds.Nef_Rune, ItemClassIds.Sol_Rune, ItemClassIds.Ith_Rune], // Nef + Sol + Ith + Rhyme: [ItemClassIds.Shael_Rune, ItemClassIds.Eth_Rune], // Shael + Eth + Silence: [ItemClassIds.Dol_Rune, ItemClassIds.Eld_Rune, ItemClassIds.Hel_Rune, ItemClassIds.Ist_Rune, ItemClassIds.Tir_Rune, ItemClassIds.Vex_Rune], // Dol + Eld + Hel + Ist + Tir + Vex + Smoke: [ItemClassIds.Nef_Rune, ItemClassIds.Lum_Rune], // Nef + Lum + Stealth: [ItemClassIds.Tal_Rune, ItemClassIds.Eth_Rune], // Tal + Eth + Steel: [ItemClassIds.Tir_Rune, ItemClassIds.El_Rune], // Tir + El + Strength: [ItemClassIds.Amn_Rune, ItemClassIds.Tir_Rune], // Amn + Tir + Venom: [ItemClassIds.Tal_Rune, ItemClassIds.Dol_Rune, ItemClassIds.Mal_Rune], // Tal + Dol + Mal + Wealth: [ItemClassIds.Lem_Rune, ItemClassIds.Ko_Rune, ItemClassIds.Tir_Rune], // Lem + Ko + Tir + White: [ItemClassIds.Dol_Rune, ItemClassIds.Io_Rune], // Dol + Io + Zephyr: [ItemClassIds.Ort_Rune, ItemClassIds.Eth_Rune], // Ort + Eth + // 1.10 - Beast: [639, 612, 631, 632, 626], // Ber + Tir + Um + Mal + Lum - Bramble: [617, 636, 638, 614], // Ral + Ohm + Sur + Eth - BreathoftheDying: [635, 624, 610, 611, 642, 614], // Vex + Hel + El + Eld + Zod + Eth - CallToArms: [620, 617, 632, 633, 636], // Amn + Ral + Mal + Ist + Ohm - ChainsofHonor: [623, 631, 639, 633], // Dol + Um + Ber + Ist - Chaos: [628, 636, 631], // Fal + Ohm + Um - CrescentMoon: [622, 631, 612], // Shael + Um + Tir - Delirium: [629, 633, 625], // Lem + Ist + Io - Doom: [624, 636, 631, 637, 641], // Hel + Ohm + Um + Lo + Cham - Duress: [622, 631, 619], // Shael + Um + Thul - Enigma: [640, 615, 639], // Jah + Ith + Ber - Eternity: [620, 639, 633, 621, 638], // Amn + Ber + Ist + Sol + Sur - Exile: [635, 636, 633, 623], // Vex + Ohm + Ist + Dol - Famine: [628, 636, 618, 640], // Fal + Ohm + Ort + Jah - Gloom: [628, 631, 630], // Fal + Um + Pul - HandofJustice: [638, 641, 620, 637], // Sur + Cham + Amn + Lo - HeartoftheOak: [627, 635, 630, 619], // Ko + Vex + Pul + Thul - Kingslayer: [632, 631, 634, 628], // Mal + Um + Gul + Fal - Passion: [623, 618, 611, 629], // Dol + Ort + Eld + Lem - Prudence: [632, 612], // Mal + Tir - Sanctuary: [627, 627, 632], // Ko + Ko + Mal - 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 + Beast: [ItemClassIds.Ber_Rune, ItemClassIds.Tir_Rune, ItemClassIds.Um_Rune, ItemClassIds.Mal_Rune, ItemClassIds.Lum_Rune], // Ber + Tir + Um + Mal + Lum + Bramble: [ItemClassIds.Ral_Rune, ItemClassIds.Ohm_Rune, ItemClassIds.Sur_Rune, ItemClassIds.Eth_Rune], // Ral + Ohm + Sur + Eth + BreathoftheDying: [ItemClassIds.Vex_Rune, ItemClassIds.Hel_Rune, ItemClassIds.El_Rune, ItemClassIds.Eld_Rune, ItemClassIds.Zod_Rune, ItemClassIds.Eth_Rune], // Vex + Hel + El + Eld + Zod + Eth + CallToArms: [ItemClassIds.Amn_Rune, ItemClassIds.Ral_Rune, ItemClassIds.Mal_Rune, ItemClassIds.Ist_Rune, ItemClassIds.Ohm_Rune], // Amn + Ral + Mal + Ist + Ohm + ChainsofHonor: [ItemClassIds.Dol_Rune, ItemClassIds.Um_Rune, ItemClassIds.Ber_Rune, ItemClassIds.Ist_Rune], // Dol + Um + Ber + Ist + Chaos: [ItemClassIds.Fal_Rune, ItemClassIds.Ohm_Rune, ItemClassIds.Um_Rune], // Fal + Ohm + Um + CrescentMoon: [ItemClassIds.Shael_Rune, ItemClassIds.Um_Rune, ItemClassIds.Tir_Rune], // Shael + Um + Tir + Delirium: [ItemClassIds.Lem_Rune, ItemClassIds.Ist_Rune, ItemClassIds.Io_Rune], // Lem + Ist + Io + Doom: [ItemClassIds.Hel_Rune, ItemClassIds.Ohm_Rune, ItemClassIds.Um_Rune, ItemClassIds.Lo_Rune, ItemClassIds.Cham_Rune], // Hel + Ohm + Um + Lo + Cham + Duress: [ItemClassIds.Shael_Rune, ItemClassIds.Um_Rune, ItemClassIds.Thul_Rune], // Shael + Um + Thul + Enigma: [ItemClassIds.Jah_Rune, ItemClassIds.Ith_Rune, ItemClassIds.Ber_Rune], // Jah + Ith + Ber + Eternity: [ItemClassIds.Amn_Rune, ItemClassIds.Ber_Rune, ItemClassIds.Ist_Rune, ItemClassIds.Sol_Rune, ItemClassIds.Sur_Rune], // Amn + Ber + Ist + Sol + Sur + Exile: [ItemClassIds.Vex_Rune, ItemClassIds.Ohm_Rune, ItemClassIds.Ist_Rune, ItemClassIds.Dol_Rune], // Vex + Ohm + Ist + Dol + Famine: [ItemClassIds.Fal_Rune, ItemClassIds.Ohm_Rune, ItemClassIds.Ort_Rune, ItemClassIds.Jah_Rune], // Fal + Ohm + Ort + Jah + Gloom: [ItemClassIds.Fal_Rune, ItemClassIds.Um_Rune, ItemClassIds.Pul_Rune], // Fal + Um + Pul + HandofJustice: [ItemClassIds.Sur_Rune, ItemClassIds.Cham_Rune, ItemClassIds.Amn_Rune, ItemClassIds.Lo_Rune], // Sur + Cham + Amn + Lo + HeartoftheOak: [ItemClassIds.Ko_Rune, ItemClassIds.Vex_Rune, ItemClassIds.Pul_Rune, ItemClassIds.Thul_Rune], // Ko + Vex + Pul + Thul + Kingslayer: [ItemClassIds.Mal_Rune, ItemClassIds.Um_Rune, ItemClassIds.Gul_Rune, ItemClassIds.Fal_Rune], // Mal + Um + Gul + Fal + Passion: [ItemClassIds.Dol_Rune, ItemClassIds.Ort_Rune, ItemClassIds.Eld_Rune, ItemClassIds.Lem_Rune], // Dol + Ort + Eld + Lem + Prudence: [ItemClassIds.Mal_Rune, ItemClassIds.Tir_Rune], // Mal + Tir + Sanctuary: [ItemClassIds.Ko_Rune, ItemClassIds.Ko_Rune, ItemClassIds.Mal_Rune], // Ko + Ko + Mal + Splendor: [ItemClassIds.Eth_Rune, ItemClassIds.Lum_Rune], // Eth + Lum + Stone: [ItemClassIds.Shael_Rune, ItemClassIds.Um_Rune, ItemClassIds.Pul_Rune, ItemClassIds.Lum_Rune], // Shael + Um + Pul + Lum + Wind: [ItemClassIds.Sur_Rune, ItemClassIds.El_Rune], // Sur + El + + // Don't use ladder-only on NL + Brand: me.ladder ? [ItemClassIds.Jah_Rune, ItemClassIds.Lo_Rune, ItemClassIds.Mal_Rune, ItemClassIds.Gul_Rune] : false, // Jah + Lo + Mal + Gul + Death: me.ladder ? [ItemClassIds.Hel_Rune, ItemClassIds.El_Rune, ItemClassIds.Vex_Rune, ItemClassIds.Ort_Rune, ItemClassIds.Gul_Rune] : false, // Hel + El + Vex + Ort + Gul + Destruction: me.ladder ? [ItemClassIds.Vex_Rune, ItemClassIds.Lo_Rune, ItemClassIds.Ber_Rune, ItemClassIds.Jah_Rune, ItemClassIds.Ko_Rune] : false, // Vex + Lo + Ber + Jah + Ko + Dragon: me.ladder ? [ItemClassIds.Sur_Rune, ItemClassIds.Lo_Rune, ItemClassIds.Sol_Rune] : false, // Sur + Lo + Sol + Dream: me.ladder ? [ItemClassIds.Io_Rune, ItemClassIds.Jah_Rune, ItemClassIds.Pul_Rune] : false, // Io + Jah + Pul + Edge: me.ladder ? [ItemClassIds.Tir_Rune, ItemClassIds.Tal_Rune, ItemClassIds.Amn_Rune] : false, // Tir + Tal + Amn + Faith: me.ladder ? [ItemClassIds.Ohm_Rune, ItemClassIds.Jah_Rune, ItemClassIds.Lem_Rune, ItemClassIds.Eld_Rune] : false, // Ohm + Jah + Lem + Eld + Fortitude: me.ladder ? [ItemClassIds.El_Rune, ItemClassIds.Sol_Rune, ItemClassIds.Dol_Rune, ItemClassIds.Lo_Rune] : false, // El + Sol + Dol + Lo + Grief: me.ladder ? [ItemClassIds.Eth_Rune, ItemClassIds.Tir_Rune, ItemClassIds.Lo_Rune, ItemClassIds.Mal_Rune, ItemClassIds.Ral_Rune] : false, // Eth + Tir + Lo + Mal + Ral + Harmony: me.ladder ? [ItemClassIds.Tir_Rune, ItemClassIds.Ith_Rune, ItemClassIds.Sol_Rune, ItemClassIds.Ko_Rune] : false, // Tir + Ith + Sol + Ko + Ice: me.ladder ? [ItemClassIds.Amn_Rune, ItemClassIds.Shael_Rune, ItemClassIds.Jah_Rune, ItemClassIds.Lo_Rune] : false, // Amn + Shael + Jah + Lo + "Infinity": me.ladder ? [ItemClassIds.Ber_Rune, ItemClassIds.Mal_Rune, ItemClassIds.Ber_Rune, ItemClassIds.Ist_Rune] : false, // Ber + Mal + Ber + Ist + Insight: me.ladder ? [ItemClassIds.Ral_Rune, ItemClassIds.Tir_Rune, ItemClassIds.Tal_Rune, ItemClassIds.Sol_Rune] : false, // Ral + Tir + Tal + Sol + LastWish: me.ladder ? [ItemClassIds.Jah_Rune, ItemClassIds.Mal_Rune, ItemClassIds.Jah_Rune, ItemClassIds.Sur_Rune, ItemClassIds.Jah_Rune, ItemClassIds.Ber_Rune] : false, // Jah + Mal + Jah + Sur + Jah + Ber + Lawbringer: me.ladder ? [ItemClassIds.Amn_Rune, ItemClassIds.Lem_Rune, ItemClassIds.Ko_Rune] : false, // Amn + Lem + Ko + Oath: me.ladder ? [ItemClassIds.Shael_Rune, ItemClassIds.Pul_Rune, ItemClassIds.Mal_Rune, ItemClassIds.Lum_Rune] : false, // Shael + Pul + Mal + Lum + Obedience: me.ladder ? [ItemClassIds.Hel_Rune, ItemClassIds.Ko_Rune, ItemClassIds.Thul_Rune, ItemClassIds.Eth_Rune, ItemClassIds.Fal_Rune] : false, // Hel + Ko + Thul + Eth + Fal + Phoenix: me.ladder ? [ItemClassIds.Vex_Rune, ItemClassIds.Vex_Rune, ItemClassIds.Lo_Rune, ItemClassIds.Jah_Rune] : false, // Vex + Vex + Lo + Jah + Pride: me.ladder ? [ItemClassIds.Cham_Rune, ItemClassIds.Sur_Rune, ItemClassIds.Io_Rune, ItemClassIds.Lo_Rune] : false, // Cham + Sur + Io + Lo + Rift: me.ladder ? [ItemClassIds.Hel_Rune, ItemClassIds.Ko_Rune, ItemClassIds.Lem_Rune, ItemClassIds.Gul_Rune] : false, // Hel + Ko + Lem + Gul + Spirit: me.ladder ? [ItemClassIds.Tal_Rune, ItemClassIds.Thul_Rune, ItemClassIds.Ort_Rune, ItemClassIds.Amn_Rune] : false, // Tal + Thul + Ort + Amn + VoiceofReason: me.ladder ? [ItemClassIds.Lem_Rune, ItemClassIds.Ko_Rune, ItemClassIds.El_Rune, ItemClassIds.Eld_Rune] : false, // Lem + Ko + El + Eld + Wrath: me.ladder ? [ItemClassIds.Pul_Rune, ItemClassIds.Lum_Rune, ItemClassIds.Ber_Rune, ItemClassIds.Mal_Rune] : false, // Pul + Lum + Ber + Mal + // 1.11 - Bone: [621, 631, 631], // Sol + Um + Um - Enlightenment: [630, 617, 621], // Pul + Ral + Sol - Myth: [624, 620, 613], // Hel + Amn + Nef - Peace: [622, 619, 620], // Shael + Thul + Amn - Principle: [617, 634, 611], // Ral + Gul + Eld - Rain: [618, 632, 615], // Ort + Mal + Ith - Treachery: [622, 619, 629], // Shael + Thul + Lem + Bone: [ItemClassIds.Sol_Rune, ItemClassIds.Um_Rune, ItemClassIds.Um_Rune], // Sol + Um + Um + Enlightenment: [ItemClassIds.Pul_Rune, ItemClassIds.Ral_Rune, ItemClassIds.Sol_Rune], // Pul + Ral + Sol + Myth: [ItemClassIds.Hel_Rune, ItemClassIds.Amn_Rune, ItemClassIds.Nef_Rune], // Hel + Amn + Nef + Peace: [ItemClassIds.Shael_Rune, ItemClassIds.Thul_Rune, ItemClassIds.Amn_Rune], // Shael + Thul + Amn + Principle: [ItemClassIds.Ral_Rune, ItemClassIds.Gul_Rune, ItemClassIds.Eld_Rune], // Ral + Gul + Eld + Rain: [ItemClassIds.Ort_Rune, ItemClassIds.Mal_Rune, ItemClassIds.Ith_Rune], // Ort + Mal + Ith + Treachery: [ItemClassIds.Shael_Rune, ItemClassIds.Thul_Rune, ItemClassIds.Lem_Rune], // Shael + Thul + Lem - Test: [624, 624, 624] -} + Test: [ItemClassIds.Hel_Rune, ItemClassIds.Hel_Rune, ItemClassIds.Hel_Rune] +}; var Runewords = { needList: [], @@ -100,25 +106,58 @@ 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(NTIPParseLineInt(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 (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; + } + } + } } this.buildLists(); }, + validItem: function (item) { + if (CraftingSystem.validGids.indexOf(item.gid) > -1) { + return false; + } + + return true; + }, + // build a list of needed runes. won't count runes until the base item is found for a given runeword buildLists: function () { var i, j, k, items, hel, baseCheck; this.validGids = []; this.needList = []; - items = me.findItems(-1, 0); + items = me.findItems(-1, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); for (i = 0; i < Config.Runewords.length; i += 1) { if (!baseCheck) { @@ -126,12 +165,15 @@ var Runewords = { } if (this.getBase(Config.Runewords[i][0], Config.Runewords[i][1])) { -RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { +RuneLoop: + for (j = 0; j < Config.Runewords[i][0].length; j += 1) { for (k = 0; k < items.length; k += 1) { - if (items[k].classid === Config.Runewords[i][0][j]) { + if (items[k].classid === Config.Runewords[i][0][j] && this.validItem(items[k])) { this.validGids.push(items[k].gid); items.splice(k, 1); + k -= 1; + continue RuneLoop; } } @@ -143,11 +185,11 @@ RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { // hel rune for rerolling purposes if (baseCheck) { - hel = me.getItem(624, 0); + hel = me.getItem(ItemClassIds.Hel_Rune, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); if (hel) { do { - if (this.validGids.indexOf(hel.gid) === -1) { + if (this.validGids.indexOf(hel.gid) === -1 && this.validItem(hel)) { this.validGids.push(hel.gid); return; @@ -155,7 +197,7 @@ RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { } while (hel.getNext()); } - this.needList.push(624); + this.needList.push(ItemClassIds.Hel_Rune); } }, @@ -166,6 +208,8 @@ RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { if (this.needList[i] === classid) { this.needList.splice(i, 1); + i -= 1; + break; } } @@ -177,7 +221,7 @@ RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { checkRunewords: function () { var i, j, k, items, base, itemList; - items = me.findItems(-1, 0); // get items in inventory/stash + items = me.findItems(-1, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); // get items in inventory/stash for (i = 0; i < Config.Runewords.length; i += 1) { itemList = []; // reset item list @@ -186,12 +230,15 @@ RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { if (base) { itemList.push(base); // push the base -RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { +RuneLoop: + for (j = 0; j < Config.Runewords[i][0].length; j += 1) { for (k = 0; k < items.length; k += 1) { if (items[k].classid === Config.Runewords[i][0][j]) { // rune matched itemList.push(items[k]); // push into the item list items.splice(k, 1); // remove from item list as to not count it twice + k -= 1; + break; // stop item cycle - we found the item } } @@ -215,21 +262,10 @@ RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { return false; } - var i; - - if (unit.itemType === 74 && this.needList.indexOf(unit.classid) > -1) { // rune + if (unit.itemType === NTItemTypes.rune && this.needList.indexOf(unit.classid) > -1) { // rune return true; } - // this code will be able to limit base item pickup - /*if (unit.quality < 4 && NTIPCheckItem(unit)) { - for (i = 0; i < Config.Runewords.length; i += 1) { - if (this.getBase(Config.Runewords[i][0], unit)) { - return true; - } - } - }*/ - return false; }, @@ -247,17 +283,17 @@ RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { if (typeof base === "object") { item = base; } else { - item = me.getItem(base, 0); + item = me.getItem(base, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); } if (item) { do { - if (item && item.quality < 4 && item.getStat(194) === runeword.length) { + if (item && item.quality < ItemQuality.Magic && item.getStat(Stats.item_numsockets) === runeword.length) { /* check if item has items socketed in it better check than getFlag(0x4000000) because randomly socketed items return false for it */ - if (reroll && item.getItem() && !NTIPCheckItem(item, this.pickitEntries)) { + if (reroll && item.getItem() && !NTIP.CheckItem(item, this.pickitEntries)) { return copyUnit(item); } @@ -300,7 +336,7 @@ RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { getScroll: function () { var i, scroll, npc; - scroll = me.getItem(529, 0); // check if we already have the scroll + scroll = me.getItem(ItemClassIds.Scroll_Of_Town_Portal, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); // check if we already have the scroll if (scroll) { return scroll; @@ -312,13 +348,13 @@ RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { return false; } - scroll = npc.getItem(529); + scroll = npc.getItem(ItemClassIds.Scroll_Of_Town_Portal); if (scroll) { for (i = 0; i < 3; i += 1) { scroll.buy(true); - if (me.getItem(529)) { + if (me.getItem(ItemClassIds.Scroll_Of_Town_Portal)) { break; } } @@ -326,7 +362,7 @@ RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { me.cancel(); - return me.getItem(529, 0); + return me.getItem(ItemClassIds.Scroll_Of_Town_Portal, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); }, makeRunewords: function () { @@ -353,11 +389,12 @@ RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { this.socketItem(items[0], items[i]); } - print("ÿc4Runewords: ÿc0Made runeword: " + items[0].fname.split("\n").reverse().join(" ").replace(/ÿc./, "")); - D2Bot.printToConsole("Made runeword: " + items[0].fname.split("\n").reverse().join(" ").replace(/ÿc./, "") + ";3"); + print("ÿc4Runewords: ÿc0Made runeword: " + items[0].fname.split("\n").reverse().join(" ").replace(/ÿc[0-9!"+<;.*]/, "")); + D2Bot.printToConsole("Made runeword: " + items[0].fname.split("\n").reverse().join(" ").replace(/ÿc[0-9!"+<;.*]/, ""), 5); - if (NTIPCheckItem(items[0], this.pickitEntries)) { - Misc.logItem("Runeword kept", items[0]); + if (NTIP.CheckItem(items[0], this.pickitEntries)) { + Misc.itemLogger("Runeword Kept", items[0]); + Misc.logItem("Runeword Kept", items[0]); } } @@ -372,7 +409,7 @@ RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { var i, base, scroll, hel; for (i = 0; i < Config.Runewords.length; i += 1) { - hel = me.getItem(624, 0); + hel = me.getItem(ItemClassIds.Hel_Rune, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); if (!hel) { return false; @@ -384,7 +421,7 @@ RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { scroll = this.getScroll(); // failed to get scroll or open stash most likely means we're stuck somewhere in town, so it's better to return false - if (!scroll || !Town.openStash() || !Cubing.emptyCube()) { + if (!scroll || !Town.openStash() || !Cubing.emptyCube()) { return false; } @@ -397,8 +434,8 @@ RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { return false; } - print("ÿc4Runewords: ÿc0Rerolling runeword: " + base.fname.split("\n").reverse().join(" ").replace(/ÿc./, "")); - D2Bot.printToConsole("Rerolling runeword:" + base.fname.split("\n").reverse().join(" ").replace(/ÿc./, "") + ";3"); + print("ÿc4Runewords: ÿc0Rerolling runeword: " + base.fname.split("\n").reverse().join(" ").replace(/ÿc[0-9!"+<;.*]/, "")); + D2Bot.printToConsole("Rerolling runeword: " + base.fname.split("\n").reverse().join(" ").replace(/ÿc[0-9!"+<;.*]/, ""), 5); transmute(); delay(500); @@ -410,9 +447,9 @@ RuneLoop: for (j = 0; j < Config.Runewords[i][0].length; j += 1) { this.buildLists(); - while (getUIFlag(0x1A) || getUIFlag(0x19)) { + while (getUIFlag(UIFlags.Cube_is_open) || getUIFlag(UIFlags.Stash_is_open)) { me.cancel(); - delay(300) + delay(300); } return true; diff --git a/d2bs/kolbot/libs/common/Storage.js b/d2bs/kolbot/libs/common/Storage.js index eac52b239..0d6a7ef81 100644 --- a/d2bs/kolbot/libs/common/Storage.js +++ b/d2bs/kolbot/libs/common/Storage.js @@ -31,7 +31,7 @@ var Container = function (name, width, height, location) { var x, y; //Make sure it is in this container. - if (item.location !== this.location || item.mode !== 0) { + if (item.location !== this.location || item.mode !== ItemModes.Item_In_Inventory_Stash_Cube_Or_Store) { return false; } @@ -49,6 +49,45 @@ var Container = function (name, width, height, location) { return true; }; + /* Container.isLocked(item) + * Checks if the item is in a locked spot + */ + this.IsLocked = function (item, baseRef) { + var h, w, reference; + + reference = baseRef.slice(0); + + //Make sure it is in this container. + if (item.mode !== ItemModes.Item_In_Inventory_Stash_Cube_Or_Store || item.location !== this.location) { + return false; + } + + // Make sure the item is ours + if (!item.getParent() || item.getParent().gid !== me.gid) { + return false; + } + + //Insure valid reference. + if (typeof (reference) !== "object" || reference.length !== this.buffer.length || reference[0].length !== this.buffer[0].length) { + throw new Error("Storage.IsLocked: Invalid inventory reference"); + } + + try { + // Check if the item lies in a locked spot. + for (h = item.y; h < (item.y + item.sizey); h += 1) { + for (w = item.x; w < (item.x + item.sizex); w += 1) { + if (reference[h][w] === 0) { + return true; + } + } + } + } catch (e2) { + throw new Error("Storage.IsLocked error! Item info: " + item.name + " " + item.y + " " + item.sizey + " " + item.x + " " + item.sizex + " " + item.mode + " " + item.location); + } + + return false; + }; + this.Reset = function () { var h, w; @@ -83,9 +122,9 @@ var Container = function (name, width, height, location) { Storage.Reload(); //Loop buffer looking for spot to place item. - for (x = 0; x < this.height - (item.sizey - 1); x += 1) { + for (y = 0; y < this.width - (item.sizex - 1); y += 1) { Loop: - for (y = 0; y < this.width - (item.sizex - 1); y += 1) { + for (x = 0; x < this.height - (item.sizey - 1); x += 1) { //Check if there is something in this spot. if (this.buffer[x][y] > 0) { continue; @@ -122,12 +161,12 @@ Loop: } //Can't deal with items on ground! - if (item.mode === 3) { + if (item.mode === ItemModes.Item_on_ground) { return false; } //Item already on the cursor. - if (me.itemoncursor && item.mode !== 4) { + if (me.itemoncursor && item.mode !== ItemModes.Item_on_cursor) { return false; } @@ -140,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); @@ -178,6 +217,27 @@ Loop: } }; + /* Container.UsedSpacePercent() + * Returns percentage of the container used. + */ + this.UsedSpacePercent = function () { + var x, y, + usedSpace = 0, + totalSpace = this.height * this.width; + + Storage.Reload(); + + for (x = 0; x < this.height; x += 1) { + for (y = 0; y < this.width; y += 1) { + if (this.buffer[x][y] > 0) { + usedSpace += 1; + } + } + } + + return usedSpace * 100 / totalSpace; + }; + /* Container.compare(reference) * Compare given container versus the current one, return all new items in current buffer. */ @@ -230,8 +290,9 @@ Loop: var Storage = new function () { this.Init = function () { - this.StashY = me.gametype === 0 ? 4 : 8; + this.StashY = me.gametype === GameType.Classic ? 4 : 8; this.Inventory = new Container("Inventory", 10, 4, 3); + this.TradeScreen = new Container("Inventory", 10, 4, 5); this.Stash = new Container("Stash", 6, this.StashY, 7); this.Belt = new Container("Belt", 4 * this.BeltSize(), 1, 2); this.Cube = new Container("Horadric Cube", 3, 4, 6); @@ -240,15 +301,15 @@ var Storage = new function () { this.Reload(); }; - this.BeltSize = function () { - var item = me.getItem(-1, 1); // get equipped item + this.BeltSize = function() { + var item = me.getItem(-1, ItemModes.Item_equipped_self_or_merc); // get equipped item if (!item) { // nothing equipped return 1; } do { - if (item.bodylocation === 8) { // belt slot + if (item.bodylocation === ItemBodyLocation.BELT) { // belt slot switch (item.code) { case "lbl": // sash case "vbl": // light belt @@ -270,25 +331,35 @@ var Storage = new function () { this.Stash.Reset(); this.Belt.Reset(); this.Cube.Reset(); + this.TradeScreen.Reset(); + var item = me.getItem(); if (!item) { return false; } - + do { switch (item.location) { - case 3: + case ItemLocation.Inventory: this.Inventory.Mark(item); + break; - case 2: + case ItemLocation.Trade: + this.TradeScreen.Mark(item); + + break; + case ItemLocation.Belt: this.Belt.Mark(item); + break; - case 6: + case ItemLocation.Cube: this.Cube.Mark(item); + break; - case 7: + case ItemLocation.Stash: this.Stash.Mark(item); + break; } } while (item.getNext()); diff --git a/d2bs/kolbot/libs/common/Town.js b/d2bs/kolbot/libs/common/Town.js index 5a8492ada..9e96732b0 100644 --- a/d2bs/kolbot/libs/common/Town.js +++ b/d2bs/kolbot/libs/common/Town.js @@ -28,67 +28,139 @@ var NPC = { Malah: getLocaleString(22478).toLowerCase(), Anya: getLocaleString(22477).toLowerCase(), Larzuk: getLocaleString(22476).toLowerCase(), - "Qual-Kehk": getLocaleString(22480).toLowerCase() + "Qual-Kehk": getLocaleString(22480).toLowerCase(), + + Cain: getLocaleString(2890).toLowerCase() }; var Town = { + telekinesis: true, sellTimer: getTickCount(), // shop speedup test tasks: [ - {Heal: NPC.Akara, Shop: NPC.Akara, Gamble: NPC.Gheed, Repair: NPC.Charsi, Merc: NPC.Kashya, Key: NPC.Akara}, - {Heal: NPC.Fara, Shop: NPC.Drognan, Gamble: NPC.Elzix, Repair: NPC.Fara, Merc: NPC.Greiz, Key: NPC.Lysander}, - {Heal: NPC.Ormus, Shop: NPC.Ormus, Gamble: NPC.Alkor, Repair: NPC.Hratli, Merc: NPC.Asheara, Key: NPC.Hratli}, - {Heal: NPC.Jamella, Shop: NPC.Jamella, Gamble: NPC.Jamella, Repair: NPC.Halbu, Merc: NPC.Tyrael, Key: NPC.Jamella}, - {Heal: NPC.Malah, Shop: NPC.Malah, Gamble: NPC.Anya, Repair: NPC.Larzuk, Merc: NPC["Qual-Kehk"], Key: NPC.Malah} + {Heal: NPC.Akara, Shop: NPC.Akara, Gamble: NPC.Gheed, Repair: NPC.Charsi, Merc: NPC.Kashya, Key: NPC.Akara, CainID: NPC.Cain}, + {Heal: NPC.Fara, Shop: NPC.Drognan, Gamble: NPC.Elzix, Repair: NPC.Fara, Merc: NPC.Greiz, Key: NPC.Lysander, CainID: NPC.Cain}, + {Heal: NPC.Ormus, Shop: NPC.Ormus, Gamble: NPC.Alkor, Repair: NPC.Hratli, Merc: NPC.Asheara, Key: NPC.Hratli, CainID: NPC.Cain}, + {Heal: NPC.Jamella, Shop: NPC.Jamella, Gamble: NPC.Jamella, Repair: NPC.Halbu, Merc: NPC.Tyrael, Key: NPC.Jamella, CainID: NPC.Cain}, + {Heal: NPC.Malah, Shop: NPC.Malah, Gamble: NPC.Anya, Repair: NPC.Larzuk, Merc: NPC["Qual-Kehk"], Key: NPC.Malah, CainID: NPC.Cain} ], ignoredItemTypes: [ // Items that won't be stashed - 5, // Arrows - 6, // Bolts - 18, // Book (Tome) - 22, // Scroll - 38, // Missile Potion - 41, // Key - 76, // Healing Potion - 77, // Mana Potion - 78, // Rejuvenation Potion - 79, // Stamina Potion - 80, // Antidote Potion - 81 // Thawing Potion + NTItemTypes.bowquiver, // Arrows + NTItemTypes.crossbowquiver, // Bolts + NTItemTypes.book, // Book (Tome) + NTItemTypes.scroll, // Scroll + NTItemTypes.missilepotion, // Missile Potion + NTItemTypes.key, // Key + NTItemTypes.healingpotion, // Healing Potion + NTItemTypes.manapotion, // Mana Potion + NTItemTypes.rejuvpotion, // Rejuvenation Potion + NTItemTypes.staminapotion, // Stamina Potion + NTItemTypes.antidotepotion, // Antidote Potion + NTItemTypes.thawingpotion // Thawing Potion ], // Do town chores doChores: function () { - if (me.classid === 4 && Config.FindItem && Config.FindItemSwitch) { // weapon switch fix in case last game dropped with item find switch on + if (!me.inTown) { + this.goToTown(); + } + + var i, + cancelFlags = [0x01, 0x02, 0x04, 0x08, 0x14, 0x16, 0x0c, 0x0f, 0x19, 0x1a]; + + if (me.classid === ClassID.Barbarian && Config.FindItem && Config.FindItemSwitch) { // weapon switch fix in case last game dropped with item find switch on Precast.weaponSwitch(Math.abs(Config.FindItemSwitch - 1)); } + if (Config.MFSwitchPercent) { + Precast.weaponSwitch(Math.abs(Config.MFSwitch - 1)); + } + + if (Precast.haveCTA > -1) { + Precast.weaponSwitch(Math.abs(Precast.haveCTA - 1)); + } + this.heal(); - this.fillTome("tbk"); + this.identify(); + this.shopItems(); + this.fillTome(ItemClassIds.Tome_Of_Town_Portal); if (Config.FieldID) { - this.fillTome("ibk"); + this.fillTome(ItemClassIds.Tome_Of_Identify); } this.buyPotions(); - this.identify(); - this.shopItems(); - this.repair(); + this.clearInventory(); + Item.autoEquip(); this.buyKeys(); + this.repair(); this.gamble(); this.reviveMerc(); Cubing.doCubing(); Runewords.makeRunewords(); this.stash(true); + this.clearScrolls(); - while (getUIFlag(0x08) || getUIFlag(0x1A) || getUIFlag(0x19)) { - me.cancel(); - delay(300); + for (i = 0; i < cancelFlags.length; i += 1) { + if (getUIFlag(cancelFlags[i])) { + delay(500); + me.cancel(); + + break; + } + } + + me.cancel(); + + return true; + }, + + checkQuestItems: function () { + var i, npc, item; + + // golden bird stuff + if (me.getItem(ItemClassIds.A_Jade_Figurine)) { + this.goToTown(3); + this.move("meshif"); + + npc = getUnit(1, "meshif"); + + if (npc) { + npc.openMenu(); + me.cancel(); + } + } + + if (me.getItem(ItemClassIds.The_Golden_Bird)) { + this.goToTown(3); + this.move("alkor"); + + npc = getUnit(UnitType.NPC, "alkor"); + + if (npc) { + for (i = 0; i < 2; i += 1) { + npc.openMenu(); + me.cancel(); + } + } + } + + if (me.getItem(ItemClassIds.Potion_of_Life)) { + item = me.getItem(ItemClassIds.Potion_of_Life); + + if (item.location > ItemLocation.Inventory) { + 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]) { @@ -97,13 +169,24 @@ var Town = { npc = null; } + // Jamella gamble fix + if (task === "Gamble" && npc && npc.name.toLowerCase() === NPC.Jamella) { + me.cancel(); + + npc = null; + } + if (!npc) { - this.move(this.tasks[me.act - 1][task]); + npc = getUnit(UnitType.NPC, this.tasks[me.act - 1][task]); + + if (!npc) { + this.move(this.tasks[me.act - 1][task]); - npc = getUnit(1, this.tasks[me.act - 1][task]); + npc = getUnit(UnitType.NPC, this.tasks[me.act - 1][task]); + } } - if (!npc || (!getUIFlag(0x08) && !npc.openMenu())) { + if (!npc || npc.area !== me.area || (!getUIFlag(UIFlags.npc_menu) && !npc.openMenu())) { return false; } @@ -111,16 +194,21 @@ var Town = { case "Shop": case "Repair": case "Gamble": - if (!getUIFlag(0x0C) && !npc.startTrade(task)) { + if (!getUIFlag(UIFlags.Shop_open_at_NPC) && !npc.startTrade(task)) { return false; } break; case "Key": - if (!getUIFlag(0x0C) && !npc.startTrade(me.act === 3 ? "Repair" : "Shop")) { + if (!getUIFlag(UIFlags.Shop_open_at_NPC) && !npc.startTrade(me.act === 3 ? "Repair" : "Shop")) { return false; } + break; + case "CainID": + Misc.useMenu(NPCMenu.Identify_Items); + me.cancel(); + break; } @@ -133,7 +221,7 @@ var Town = { return true; } - if (!this.initNPC("Heal")) { + if (!this.initNPC("Heal", "heal")) { return false; } @@ -142,66 +230,105 @@ var Town = { // Check if healing is needed, based on character config needHealing: function () { - if (me.hp * 100 / me.hpmax > Config.HealHP && me.mp * 100 / me.mpmax > Config.HealMP) { - return false; + if (me.hp * 100 / me.hpmax <= Config.HealHP || me.mp * 100 / me.mpmax <= Config.HealMP) { + return true; } - return true; + // Status effects + if (Config.HealStatus && (me.getState(States.POISON) || me.getState(States.AMPLIFYDAMAGE) || me.getState(States.LOWERRESIST))) { + return true; + } + + return false; }, - // Buy potions from a NPC buyPotions: function () { - var i, j, pot, npc, beltSize, col, - emptyColumns = 0, - useShift = true; + if (me.gold < 1000) { // Ain't got money fo' dat shyt + return false; + } + + var i, j, npc, useShift, col, beltSize, pot, + needPots = false, + needBuffer = true, + buffer = { + hp: 0, + mp: 0 + }; - col = this.checkColumns(); beltSize = Storage.BeltSize(); + col = this.checkColumns(beltSize); + + // HP/MP Buffer + if (Config.HPBuffer > 0 || Config.MPBuffer > 0) { + pot = me.getItem(-1, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); + + if (pot) { + do { + if (pot.location === ItemLocation.Inventory) { + switch (pot.itemType) { + case NTItemTypes.healingpotion: + buffer.hp += 1; + + break; + case NTItemTypes.manapotion: + 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 - Config.MinColumn[i])) { - break; + if (["hp", "mp"].indexOf(Config.BeltColumn[i]) > -1 && col[i] > (beltSize - Math.min(Config.MinColumn[i], beltSize))) { + needPots = true; } } - if (i === 4) { - return 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; + } + } } - npc = this.initNPC("Shop"); + // We have enough potions in inventory + if (buffer.mp >= Config.MPBuffer && buffer.hp >= Config.HPBuffer) { + needBuffer = false; + } - if (!npc) { - return false; + // No columns to fill + if (!needPots && !needBuffer) { + return true; } - for (i = 0; i < 4; i += 1) { - switch (Config.BeltColumn[i]) { - case "hp": - case "mp": // Increase emptyColumns if a buyable column is empty - if (col[i] === beltSize) { - emptyColumns += 1; - } + if (me.diff === 0 && Pather.accessToAct(4) && me.act < 4) { + this.goToTown(4); + } - break; - case "rv": // can't use shift buy if "rv" column is empty - if (col[i] === beltSize) { - useShift = false; - } + npc = this.initNPC("Shop", "buyPotions"); - break; - } + if (!npc) { + return false; } for (i = 0; i < 4; i += 1) { if (col[i] > 0) { + useShift = this.shiftCheck(col, beltSize); pot = this.getPotion(npc, Config.BeltColumn[i]); if (pot) { //print("ÿc2column ÿc0" + i + "ÿc2 needs ÿc0" + col[i] + " ÿc2potions"); // Shift+buy will trigger if there's no empty columns or if only the current column is empty - if (useShift && (emptyColumns === 0 || (emptyColumns === 1 && col[i] === beltSize))) { + if (useShift) { pot.buy(true); } else { for (j = 0; j < col[i]; j += 1) { @@ -211,22 +338,79 @@ var Town = { } } - // Switch to shift+buy on the fly (if possible, happens if 2+ buyable potion columns are empty) - if (col[i] === beltSize && emptyColumns > 0) { - emptyColumns -= 1; + 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; + }, + + // Check when to shift-buy potions + shiftCheck: function (col, beltSize) { + var i, fillType; + + for (i = 0; i < col.length; i += 1) { + // Set type based on non-empty column + if (!fillType && col[i] > 0 && col[i] < beltSize) { + fillType = Config.BeltColumn[i]; } - col = this.checkColumns(); // Re-initialize columns (needed because 1 shift-buy can fill multiple columns) + if (col[i] >= beltSize) { + switch (Config.BeltColumn[i]) { + case "hp": + // Set type based on empty column + if (!fillType) { + fillType = "hp"; + } + + // Can't shift+buy if we need to get differnt potion types + if (fillType !== "hp") { + return false; + } + + break; + case "mp": + if (!fillType) { + fillType = "mp"; + } + + if (fillType !== "mp") { + return false; + } + + break; + case "rv": // Empty rejuv column = can't shift-buy + return false; + } + } } return true; }, // Return column status (needed potions in each column) - checkColumns: function () { - var beltSize = Storage.BeltSize(), - col = [beltSize, beltSize, beltSize, beltSize], - pot = me.getItem(-1, 2); // Mode 2 = in belt + checkColumns: function (beltSize) { + var col = [beltSize, beltSize, beltSize, beltSize], + pot = me.getItem(-1, ItemModes.Item_in_belt); // Mode 2 = in belt if (!pot) { // No potions return col; @@ -261,32 +445,41 @@ var Town = { }, fillTome: function (code) { - delay(500); + if (me.gold < 450) { + return false; + } - if (this.checkScrolls(code) >= 10) { + if (this.checkScrolls(code) >= 13) { return true; } var scroll, tome, - npc = this.initNPC("Shop"); + npc = this.initNPC("Shop", "fillTome"); if (!npc) { return false; } - if (!me.findItem("tbk", 0, 3)) { - tome = npc.getItem("tbk"); + delay(500); + + if (code === ItemClassIds.Tome_Of_Town_Portal && !me.findItem(ItemClassIds.Tome_Of_Town_Portal, 0, ItemLocation.Inventory)) { + tome = npc.getItem(ItemClassIds.Tome_Of_Town_Portal); - 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; } } - scroll = npc.getItem(code === "tbk" ? "tsc" : "isc"); + scroll = npc.getItem(code === ItemClassIds.Tome_Of_Town_Portal ? ItemClassIds.Scroll_Of_Town_Portal : ItemClassIds.Scroll_Of_Identify); if (!scroll) { return false; @@ -303,129 +496,164 @@ var Town = { return true; }, - checkScrolls: function (id) { - var tome = me.findItem(id, 0, 3); + checkScrolls: function(id) { + var tome = me.findItem(id, 0, ItemLocation.Inventory); if (!tome) { - return false; + switch (id) { + case ItemClassIds.Tome_Of_Identify: + case "ibk": + return 20; // Ignore missing ID tome + case ItemClassIds.Tome_Of_Town_Portal: + case "tbk": + return 0; // Force TP tome check + } } - return tome.getStat(70); + return tome.getStat(Stats.quantity); }, identify: function () { - var item, tome, scroll, npc, list, timer, tpTome, + var i, item, tome, scroll, npc, list, timer, tpTome, result, tpTomePos = {}; - if (this.cainID()) { - return true; - } + this.cainID(); - list = this.getUnids(); + list = Storage.Inventory.Compare(Config.Inventory); if (!list) { return false; } - npc = this.initNPC("Shop"); + // 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(ItemFlags.isIdentified) || Config.LowGold > 0) && ([-1, 4].indexOf(Pickit.checkItem(list[i]).result) > -1 || (!list[i].getFlag(ItemFlags.isIdentified) && Item.hasTier(list[i])))) { + break; + } + } + + if (i === list.length) { + return false; + } + + npc = this.initNPC("Shop", "identify"); if (!npc) { return false; } - tome = me.findItem("ibk", 0, 3); + tome = me.findItem(ItemClassIds.Tome_Of_Identify, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory); - if (tome && tome.getStat(70) < list.length) { - this.fillTome("ibk"); + if (tome && tome.getStat(Stats.quantity) < list.length) { + this.fillTome(ItemClassIds.Tome_Of_Identify); } MainLoop: while (list.length > 0) { item = list.shift(); - switch (Pickit.checkItem(item)) { - case 1: - if (item.getFlag(0x10)) { - //D2Bot.printToItemLog("Kept " + item.fname.split("\n").reverse().join(" ")); - Misc.logItem("Kept", item); + if (!item.getFlag(ItemFlags.isIdentified) && item.location === ItemLocation.Inventory && this.ignoredItemTypes.indexOf(item.itemType) === -1) { + result = Pickit.checkItem(item); + + // Force ID for unid items matching autoEquip criteria + if (result.result === 1 && !item.getFlag(ItemFlags.isIdentified) && Item.hasTier(item)) { + result.result = -1; } - break; - case 2: - break; - case -1: - if (tome) { - this.identifyItem(item, tome); - } else { - scroll = npc.getItem("isc"); + switch (result.result) { + // Items for gold, will sell magics, etc. w/o id, but at low levels + // magics are often not worth iding. + case 4: + Misc.itemLogger("Sold", item); + item.sell(); + + break; + case -1: + if (tome) { + this.identifyItem(item, tome); + } else { + scroll = npc.getItem(ItemClassIds.Scroll_Of_Identify); - if (scroll) { - if (!Storage.Inventory.CanFit(scroll)) { - tpTome = me.findItem("tbk", 0, 3); + if (scroll) { + if (!Storage.Inventory.CanFit(scroll)) { + tpTome = me.findItem(ItemClassIds.Tome_Of_Town_Portal, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory); - if (tpTome) { - tpTomePos = {x: tpTome.x, y: tpTome.y}; + if (tpTome) { + tpTomePos = {x: tpTome.x, y: tpTome.y}; - tpTome.sell(); - delay(500); + tpTome.sell(); + delay(500); + } + } + + delay(500); + + if (Storage.Inventory.CanFit(scroll)) { + scroll.buy(); } } - delay(500); - scroll.buy(); - } + scroll = me.findItem(ItemClassIds.Scroll_Of_Identify, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory); - scroll = me.findItem("isc", 0, 3); + if (!scroll) { + break MainLoop; + } - if (!scroll) { - break MainLoop; + this.identifyItem(item, scroll); } - this.identifyItem(item, scroll); - } + result = Pickit.checkItem(item); - switch (Pickit.checkItem(item)) { - case 1: - //D2Bot.printToItemLog("Kept " + item.fname.split("\n").reverse().join(" ")); - Misc.logItem("Kept", item); - break; - case -1: - case 2: - case 3: // just in case - break; - default: - item.sell(); + if (!Item.autoEquipCheck(item)) { + result.result = 0; + } - timer = getTickCount() - this.sellTimer; // shop speedup test + switch (result.result) { + case 1: + // Couldn't id autoEquip item. Don't log it. + if (result.result === 1 && Config.AutoEquip && !item.getFlag(ItemFlags.isIdentified) && Item.autoEquipCheck(item)) { + break; + } - //print("sell timer: " + timer); + Misc.itemLogger("Kept", item); + Misc.logItem("Kept", item, result.line); - if (timer > 0 && timer < 500) { - delay(timer); - } + break; + case -1: // unidentified + break; + case 2: // cubing + Misc.itemLogger("Kept", item, "Cubing-Town"); + Cubing.update(); - break; - } + break; + case 3: // runeword (doesn't trigger normally) + break; + case 5: // Crafting System + Misc.itemLogger("Kept", item, "CraftSys-Town"); + CraftingSystem.update(item); - break; - } - } + break; + default: + Misc.itemLogger("Sold", item); + item.sell(); - if (!me.findItem("tbk", 0, 3)) { - this.fillTome("tbk"); + timer = getTickCount() - this.sellTimer; // shop speedup test - tpTome = me.findItem("tbk", 0, 3); + if (timer > 0 && timer < 500) { + delay(timer); + } - if (tpTome) { - if (tpTome.x !== tpTomePos.x || tpTome.y !== tpTomePos.y) { - if (tpTome.toCursor()) { - clickItem(0, tpTomePos.x, tpTomePos.y, 3); - delay(300); + break; } + + break; } } } + this.fillTome(ItemClassIds.Tome_Of_Town_Portal); // Check for TP tome in case it got sold for ID scrolls + return true; }, @@ -435,7 +663,7 @@ MainLoop: } // Check if we're already in a shop. It would be pointless to go to Cain if so. - var i, cain, unids, + var i, cain, unids, result, npc = getInteractedNPC(); if (npc && npc.name.toLowerCase() === this.tasks[me.act - 1].Shop) { @@ -443,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; @@ -464,36 +692,35 @@ MainLoop: // Check if we may use Cain - kept unid items for (i = 0; i < unids.length; i += 1) { - if (Pickit.checkItem(unids[i]) > 0) { + if (Pickit.checkItem(unids[i]).result > 0) { //print("Can't use Cain - can't id a valid item."); return false; } } - this.move("cain"); - - cain = getUnit(1, getLocaleString(2890)); + cain = this.initNPC("CainID", "cainID"); if (!cain) { return false; } - if (cain && cain.openMenu()) { - delay(10); - cain.useMenu(0x0FB4); - delay(500); - me.cancel(); - } - for (i = 0; i < unids.length; i += 1) { - switch (Pickit.checkItem(unids[i])) { + result = Pickit.checkItem(unids[i]); + + if (!Item.autoEquipCheck(unids[i])) { + result = 0; + } + + switch (result.result) { case 0: + Misc.itemLogger("Dropped", unids[i], "cainID"); unids[i].drop(); break; case 1: - Misc.logItem("Kept", unids[i]); + Misc.itemLogger("Kept", unids[i]); + Misc.logItem("Kept", unids[i], result.line); break; default: @@ -506,7 +733,7 @@ MainLoop: }, fieldID: function () { // not exactly a town function but whateva - var list, tome, item; + var list, tome, item, result; list = this.getUnids(); @@ -514,26 +741,49 @@ MainLoop: return false; } - tome = me.findItem("ibk", 0, 3); + tome = me.findItem(ItemClassIds.Tome_Of_Identify, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory); - if (!tome || tome.getStat(70) < list.length) { + if (!tome || tome.getStat(Stats.quantity) < list.length) { return false; } while (list.length > 0) { item = list.shift(); + result = Pickit.checkItem(item); - if (Pickit.checkItem(item) === -1) { // unid item that should be identified + // Force ID for unid items matching autoEquip criteria + if (result.result === 1 && !item.getFlag(ItemFlags.isIdentified) && Item.hasTier(item)) { + result.result = -1; + } + + if (result.result === -1) { // unid item that should be identified this.identifyItem(item, tome); delay(me.ping + 1); - switch (Pickit.checkItem(item)) { + 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; case 1: - Misc.logItem("Field Kept", item); + Misc.itemLogger("Field Kept", item); + Misc.logItem("Field Kept", item, result.line); break; default: @@ -549,19 +799,18 @@ MainLoop: }, getUnids: function () { - var i, - list = [], - items = me.getItems(); + var list = [], + item = me.getItem(-1, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); - if (!items || !items.length) { + if (!item) { return false; } - for (i = 0; i < items.length; i += 1) { - if (items[i].location === 3 && !items[i].getFlag(0x10)) { - list.push(items[i]); + do { + if (item.location === ItemLocation.Inventory && !item.getFlag(ItemFlags.isIdentified)) { + list.push(copyUnit(item)); } - } + } while (item.getNext()); if (!list.length) { return false; @@ -571,14 +820,19 @@ MainLoop: }, identifyItem: function (unit, tome) { + if (Config.PacketShopping) { + return Packet.identifyItem(unit, tome); + } + var i, tick; - if (!unit || unit.getFlag(0x10)) { + if (!unit || unit.getFlag(ItemFlags.isIdentified)) { return false; } this.sellTimer = getTickCount(); // shop speedup test +CursorLoop: for (i = 0; i < 3; i += 1) { clickItem(1, tome); @@ -586,7 +840,7 @@ MainLoop: while (getTickCount() - tick < 500) { if (getCursorType() === 6) { - break; + break CursorLoop; } delay(10); @@ -601,13 +855,13 @@ MainLoop: for (i = 0; i < 3; i += 1) { if (getCursorType() === 6) { - clickItem(0, unit); + clickItem(ClickType.Left_Click, unit); } tick = getTickCount(); while (getTickCount() - tick < 500) { - if (unit.getFlag(0x10)) { + if (unit.getFlag(ItemFlags.isIdentified)) { delay(50); return true; @@ -627,89 +881,153 @@ MainLoop: return true; } - var i, items, + var i, item, result, + items = [], npc = getInteractedNPC(); - if (!npc) { + if (!npc || !npc.itemcount) { return false; } - items = npc.getItems(); + item = npc.getItem(); - if (!items || !items.length) { + if (!item) { return false; } - print("ÿc4MiniShopBotÿc0: Scanning " + items.length + " items."); + print("ÿc4MiniShopBotÿc0: Scanning " + npc.itemcount + " items."); + + do { + if (this.ignoredItemTypes.indexOf(item.itemType) === -1) { + items.push(copyUnit(item)); + } + } while (item.getNext()); for (i = 0; i < items.length; i += 1) { - if (this.ignoredItemTypes.indexOf(items[i].itemType) === -1 && Pickit.checkItem(items[i]) === 1) { + result = Pickit.checkItem(items[i]); + + 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.logItem("Shopped", items[i]); + if (Storage.Inventory.CanFit(items[i]) && me.getStat(Stats.gold) + me.getStat(Stats.goldbank) >= items[i].getItemCost(0)) { + Misc.itemLogger("Shopped", items[i]); + Misc.logItem("Shopped", items[i], result.line); items[i].buy(); } } catch (e) { print(e); } } + + delay(2); } return true; }, + gambleIds: [], + gamble: function () { - if (!this.needGamble() || !Config.GambleItems.length) { + if (!this.needGamble() || Config.GambleItems.length === 0) { return true; } - var i, items, npc, newItem, + var i, item, items, npc, newItem, result, list = []; - npc = this.initNPC("Gamble"); + 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", "gamble"); if (!npc) { return false; } - items = me.findItems(-1, 0, 3); + items = me.findItems(-1, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory); - 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"); } - items = npc.getItems(); + item = npc.getItem(); + items = []; + + if (item) { + do { + if (this.gambleIds.indexOf(item.classid) > -1) { + items.push(copyUnit(item)); + } + } while (item.getNext()); - if (items) { for (i = 0; i < items.length; i += 1) { - if (Config.GambleItems.indexOf(items[i].classid) > -1 && Storage.Inventory.CanFit(items[i])) { - items[i].buy(); + if (!Storage.Inventory.CanFit(items[i])) { + return false; + } - newItem = this.getGambledItem(list); + me.overhead("Buy: " + items[i].name); + items[i].buy(false, true); - if (newItem) { - switch (Pickit.checkItem(newItem)) { - case 1: - Misc.logItem("Gambled", newItem); - list.push(newItem.gid); + newItem = this.getGambledItem(list); - break; - case 2: - list.push(newItem.gid); - Cubing.buildLists(); + if (newItem) { + result = Pickit.checkItem(newItem); - break; - default: - newItem.sell(); - delay(500); + if (!Item.autoEquipCheck(newItem)) { + result = 0; + } + + switch (result.result) { + case 1: + Misc.itemLogger("Gambled", newItem); + Misc.logItem("Gambled", newItem, result.line); + list.push(newItem.gid); + + break; + case 2: + list.push(newItem.gid); + Cubing.update(); + + break; + case 5: // Crafting System + CraftingSystem.update(newItem); + + break; + default: + Misc.itemLogger("Sold", newItem, "Gambling"); + me.overhead("Sell: " + newItem.name); + newItem.sell(); - break; + if (!Config.PacketShopping) { + delay(500); } + + break; } } } @@ -722,17 +1040,17 @@ MainLoop: }, needGamble: function () { - return Config.Gamble && me.getStat(14) + me.getStat(15) >= Config.GambleGoldStart; + return Config.Gamble && me.gold >= Config.GambleGoldStart; }, getGambledItem: function (list) { var i, j, - items = me.findItems(-1, 0, 3); + items = me.findItems(-1, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory); for (i = 0; i < items.length; i += 1) { if (list.indexOf(items[i].gid) === -1) { for (j = 0; j < 3; j += 1) { - if (items[i].getFlag(0x10)) { + if (items[i].getFlag(ItemFlags.isIdentified)) { break; } @@ -747,12 +1065,17 @@ MainLoop: }, buyKeys: function () { - if (!this.needKeys()) { + if (!this.wantKeys()) { return true; } + // Fuck Hratli + if (me.act === 3) { + this.goToTown(Pather.accessToAct(4) ? 4 : 2); + } + var key, - npc = this.initNPC("Key"); + npc = this.initNPC("Key", "buyKeys"); if (!npc) { return false; @@ -775,132 +1098,233 @@ MainLoop: return true; }, - needKeys: function () { - if (!Config.OpenChests || me.classid === 6) { - return false; + checkKeys: function () { + if (!Config.OpenChests || me.classid === ClassID.Assassin || me.gold < 540 || (!me.getItem("key") && !Storage.Inventory.CanFit({sizex: 1, sizey: 1}))) { + return 12; } - var key = me.findItem("key", 0, 3); + var i, + count = 0, + key = me.findItems(ItemClassIds.Key, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory); + + if (key) { + for (i = 0; i < key.length; i += 1) { + count += key[i].getStat(Stats.quantity); + } + } + + return count; + }, + + needKeys: function () { + return this.checkKeys() <= 0; + }, + + wantKeys: function () { + return this.checkKeys() <= 6; + }, - if (key && key.getStat(70) > 6) { + repairIngredientCheck: function (item) { + if (!Config.CubeRepair) { return false; } - return true; + var needRal = 0, + needOrt = 0, + items = this.getItemsForRepair(Config.RepairPercent, false); + + if (items && items.length) { + while (items.length > 0) { + switch (items.shift().itemType) { + case NTItemTypes.shield: + case NTItemTypes.armor: + case NTItemTypes.boots: + case NTItemTypes.gloves: + case NTItemTypes.belt: + case NTItemTypes.voodooheads: + case NTItemTypes.auricshields: + case NTItemTypes.primalhelm: + case NTItemTypes.pelt: + case NTItemTypes.circlet: + needRal += 1; + + break; + default: + needOrt += 1; + + break; + } + } + } + + switch (item.classid) { + case ItemClassIds.Ral_Rune: + if (needRal && (!me.findItems(ItemClassIds.Ral_Rune) || me.findItems(ItemClassIds.Ral_Rune) < needRal)) { + return true; + } + + break; + case ItemClassIds.Ort_Rune: + if (needOrt && (!me.findItems(ItemClassIds.Ort_Rune) || me.findItems(ItemClassIds.Ort_Rune) < needOrt)) { + return true; + } + + break; + } + + return false; }, - repair: function () { - var quiver, myQuiver, npc, repairCheck, bowCheck; + cubeRepair: function () { + if (!Config.CubeRepair || !me.getItem(ItemClassIds.Horadric_Cube)) { + return false; + } - repairCheck = this.needRepair(); + var items = this.getItemsForRepair(Config.RepairPercent, false); - if (!repairCheck) { - return true; + items.sort(function (a, b) { + return a.getStat(Stats.durability) * 100 / a.getStat(Stats.maxdurability) - b.getStat(Stats.durability) * 100 / b.getStat(Stats.maxdurability); + }); + + while (items.length > 0) { + this.cubeRepairItem(items.shift()); } - npc = this.initNPC("Repair"); + return true; + }, + + cubeRepairItem: function (item) { + var i, rune, cubeItems, + bodyLoc = item.bodylocation; - if (!npc) { + if (item.mode !== 1) { return false; } - //print("Repair trigger: " + repairCheck); + switch (item.itemType) { + case NTItemTypes.shield: + case NTItemTypes.armor: + case NTItemTypes.boots: + case NTItemTypes.gloves: + case NTItemTypes.belt: + case NTItemTypes.voodooheads: + case NTItemTypes.auricshields: + case NTItemTypes.primalhelm: + case NTItemTypes.pelt: + case NTItemTypes.circlet: + rune = me.getItem(ItemClassIds.Ral_Rune); // Ral rune - switch (repairCheck) { - case "durability": - case "charges": - case "quantity": - me.repair(); + break; + default: + rune = me.getItem(ItemClassIds.Ort_Rune); // Ort rune break; - case "quiver": - bowCheck = Attack.usingBow(); + } - if (bowCheck) { - switch (bowCheck) { - case "bow": - quiver = npc.getItem("aqv"); + if (rune && Town.openStash() && Cubing.openCube() && Cubing.emptyCube()) { + for (i = 0; i < 100; i += 1) { + if (!me.itemoncursor) { + if (Storage.Cube.MoveTo(item) && Storage.Cube.MoveTo(rune)) { + transmute(); + delay(1000 + me.ping); + } - break; - case "crossbow": - quiver = npc.getItem("cqv"); + cubeItems = me.findItems(-1, -1, ItemLocation.Cube); // Get cube contents - break; + if (cubeItems.length === 1) { // We expect only one item in cube + cubeItems[0].toCursor(); + } } - if (quiver) { - myQuiver = me.getItem(quiver.code, 1); + if (me.itemoncursor) { + for (i = 0; i < 3; i += 1) { + clickItem(0, bodyLoc); + delay(me.ping * 2 + 500); - if (myQuiver) { - myQuiver.sell(); - delay(500); - } + if (cubeItems[0].bodylocation === bodyLoc) { + print(cubeItems[0].fname.split("\n").reverse().join(" ").replace(/ÿc[0-9!"+<;.*]/, "").trim() + " successfully repaired and equipped."); + D2Bot.printToConsole(cubeItems[0].fname.split("\n").reverse().join(" ").replace(/ÿc[0-9!"+<;.*]/, "").trim() + " successfully repaired and equipped.", 5); - quiver.buy(); + return true; + } + } } + + delay(200); } - break; + Misc.errorReport("Failed to put repaired item back on."); + D2Bot.stop(); } - return true; + return false; }, - needRepair: function () { - if (me.getStat(14) + me.getStat(15) < me.getRepairCost()) { // Check if we can afford repairs - return false; - } + repair: function () { + var i, quiver, myQuiver, npc, repairAction, bowCheck; - var i, durability, quantity, charge, quiver, bowCheck, - repairPercent = 40, // TODO: Move this somewhere else - item = me.getItem(-1, 1); // Id -1 = any, Mode 1 = equipped + this.cubeRepair(); - if (!item) { // No equipped items - return false; + repairAction = this.needRepair(); + + if (!repairAction || !repairAction.length) { + return true; } - do { - if (!item.getFlag(0x400000)) { // Skip ethereal items - switch (item.itemType) { - // Quantity check - case 42: // Throwing knives - case 43: // Throwing axes - case 44: // Javelins - case 87: // Amazon javelins - quantity = item.getStat(70); - - if (typeof quantity === "number" && quantity * 100 / (getBaseStat("items", item.classid, "maxstack") + item.getStat(254)) <= repairPercent) { // Stat 254 = increased stack size - return "quantity"; + 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; + case "buyQuiver": + bowCheck = Attack.usingBow(); + + if (bowCheck) { + if (bowCheck === "bow") { + quiver = "aqv"; // Arrows + } else { + quiver = "cqv"; // Bolts } - break; - // Durability check - default: - durability = item.getStat(72); + myQuiver = me.getItem(quiver, 1); - if (typeof durability === "number" && durability * 100 / item.getStat(73) <= repairPercent) { - return "durability"; + if (myQuiver) { + myQuiver.drop(); } - break; - } + npc = this.initNPC("Repair", "repair"); - // Charged item check - charge = item.getStat(-2)[204]; + if (!npc) { + return false; + } - if (typeof (charge) === "object") { - if (charge instanceof Array) { - for (i = 0; i < charge.length; i += 1) { - if (typeof charge[i] !== "undefined" && charge[i].hasOwnProperty("charges") && charge[i].charges * 100 / charge[i].maxcharges <= repairPercent) { - return "charges"; - } - } - } else if (charge.charges * 100 / charge.maxcharges <= repairPercent) { - return "charges"; + quiver = npc.getItem(quiver); + + if (quiver) { + quiver.buy(); } } + + break; } - } while (item.getNext()); + } + + //this.shopItems(); + + return true; + }, + + needRepair: function () { + var quiver, bowCheck, quantity, + repairAction = [], + canAfford = me.gold >= me.getRepairCost(); // Arrow/Bolt check bowCheck = Attack.usingBow(); @@ -908,25 +1332,91 @@ MainLoop: if (bowCheck) { switch (bowCheck) { case "bow": - quiver = me.getItem("aqv", 1); // Equipped arrow quiver + quiver = me.getItem("aqv", ItemModes.Item_equipped_self_or_merc); // Equipped arrow quiver + break; case "crossbow": - quiver = me.getItem("cqv", 1); // Equipped bolt quiver + quiver = me.getItem("cqv", ItemModes.Item_equipped_self_or_merc); // Equipped bolt quiver + break; } if (!quiver) { // Out of arrows/bolts - return "quiver"; - } + repairAction.push("buyQuiver"); + } else { + quantity = quiver.getStat(Stats.quantity); - quantity = quiver.getStat(70); + if (typeof quantity === "number" && quantity * 100 / getBaseStat("items", quiver.classid, "maxstack") <= Config.RepairPercent) { + repairAction.push("buyQuiver"); + } + } + } - if (typeof quantity === "number" && quantity * 100 / getBaseStat("items", quiver.classid, "maxstack") <= repairPercent) { - return "quiver"; + // Repair durability/quantity/charges + if (canAfford) { + if (this.getItemsForRepair(Config.RepairPercent, true).length > 0) { + repairAction.push("repair"); } + } else { + print("ÿc4Town: ÿc1Can't afford repairs."); } - return false; + return repairAction; + }, + + getItemsForRepair: function (repairPercent, chargedItems) { + var i, charge, quantity, durability, + itemList = [], + item = me.getItem(-1, ItemModes.Item_equipped_self_or_merc); + + if (item) { + do { + if (!item.getFlag(ItemFlags.isEthereal)) { // Skip ethereal items + switch (item.itemType) { + // Quantity check + case NTItemTypes.throwingknife: // Throwing knives + case NTItemTypes.throwingaxe: // Throwing axes + case NTItemTypes.javelin: // Javelins + case NTItemTypes.amazonjavelin: // Amazon javelins + quantity = item.getStat(Stats.quantity); + + if (typeof quantity === "number" && quantity * 100 / (getBaseStat("items", item.classid, "maxstack") + item.getStat(Stats.item_extra_stack)) <= repairPercent) { // Stat 254 = increased stack size + itemList.push(copyUnit(item)); + } + + break; + // Durability check + default: + durability = item.getStat(Stats.durability); + + if (typeof durability === "number" && durability * 100 / item.getStat(Stats.maxdurability) <= repairPercent) { + itemList.push(copyUnit(item)); + } + + break; + } + + if (chargedItems) { + // Charged item check + charge = item.getStat(-2)[204]; + + if (typeof (charge) === "object") { + if (charge instanceof Array) { + for (i = 0; i < charge.length; i += 1) { + if (charge[i] !== undefined && charge[i].hasOwnProperty("charges") && charge[i].charges * 100 / charge[i].maxcharges <= repairPercent) { + itemList.push(copyUnit(item)); + } + } + } else if (charge.charges * 100 / charge.maxcharges <= repairPercent) { + itemList.push(copyUnit(item)); + } + } + } + } + } while (item.getNext()); + } + + return itemList; }, reviveMerc: function () { @@ -934,40 +1424,66 @@ MainLoop: return true; } - var i, tick, - npc = this.initNPC("Merc"); + // Fuck Aheara + if (me.act === 3) { + this.goToTown(2); + } + + var i, tick, dialog, lines, + preArea = me.area, + npc = this.initNPC("Merc", "reviveMerc"); if (!npc) { return false; } - delay(300); - MainLoop: for (i = 0; i < 3; i += 1) { - npc.useMenu(0x1507); + dialog = getDialogLines(); - tick = getTickCount(); + for (lines = 0; lines < dialog.length; lines += 1) { + if (dialog[lines].text.match(":", "gi")) { + dialog[lines].handler(); + delay(Math.max(750, me.ping * 2)); + } + + // "You do not have enough gold for that." + if (dialog[lines].text.match(getLocaleString(3362), "gi")) { + return false; + } + } + + while (getTickCount() - tick < 2000) { + if (!!me.getMerc()) { + delay(Math.max(750, me.ping * 2)); - while (getTickCount() - tick < 1000) { - if (me.getMerc()) { break MainLoop; } - delay(10); + delay(200); } } - delay(300); 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 === GameType.Classic || !Config.UseMerc || me.gold < me.mercrevivecost) { // gametype 0 = classic return false; } @@ -975,7 +1491,7 @@ MainLoop: for (i = 0; i < 3; i += 1) { merc = me.getMerc(); - if (merc && merc.mode !== 0 && merc.mode !== 12) { + if (merc && merc.mode !== NPCModes.death && merc.mode !== NPCModes.dead) { return false; } @@ -989,8 +1505,18 @@ MainLoop: return true; }, + canStash: function (item) { + var ignoredClassids = [ItemClassIds.Horadric_Staff, ItemClassIds.Khalims_Will]; // 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 (!arguments.length) { + if (stashGold === undefined) { stashGold = true; } @@ -998,22 +1524,38 @@ MainLoop: return true; } - var i, + me.cancel(); + + 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 && (Pickit.checkItem(items[i]) > 0 || Cubing.keepItem(items[i]) || Runewords.keepItem(items[i]))) { - Storage.Stash.MoveTo(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]); + Storage.Stash.MoveTo(items[i]); + } } } } // Stash gold if (stashGold) { - if (me.getStat(14) >= Config.StashGold && me.getStat(15) < 25e5 && this.openStash()) { - gold(me.getStat(14), 3); - delay(500); + if (me.getStat(Stats.gold) >= Config.StashGold && me.getStat(Stats.goldbank) < 25e5 && this.openStash()) { + gold(me.getStat(Stats.gold), 3); + delay(1000); me.cancel(); } } @@ -1022,64 +1564,128 @@ MainLoop: }, needStash: function () { - return Storage.Inventory.Compare(Config.Inventory).length > 0 || (me.getStat(14) >= Config.StashGold && me.getStat(15) < 25e5); - }, + if (Config.StashGold && me.getStat(Stats.gold) >= Config.StashGold && me.getStat(Stats.goldbank) < 25e5) { + return true; + } - openStash: function () { - if (!this.move("stash")) { - return false; + var i, + items = Storage.Inventory.Compare(Config.Inventory); + + for (i = 0; i < items.length; i += 1) { + if (Storage.Stash.CanFit(items[i])) { + return true; + } } - if (getUIFlag(0x19)) { + return false; + }, + + openStash: function () { + if (getUIFlag(UIFlags.Stash_is_open)) { return true; } - var i, tick, - useTK = me.classid === 1 && me.getSkill(43, 1), - stash = getUnit(2, 267); + var i, tick, stash, + telekinesis = me.classid === ClassID.Sorceress && me.getSkill(Skills.Sorceress.Telekinesis, 1); + + for (i = 0; i < 5; i += 1) { + this.move("stash"); - if (stash) { - for (i = 0; i < 3; i += 1) { - //Pather.moveToUnit(stash, 0, 0, false, useTK); + stash = getUnit(2, UniqueObjectIds.Bank); - if (useTK) { - Skill.cast(43, 0, stash); + if (stash) { + if (telekinesis) { + Skill.cast(Skills.Sorceress.Telekinesis, 0, stash); } else { - stash.interact(); + Misc.click(0, 0, stash); + //stash.interact(); } tick = getTickCount(); while (getTickCount() - tick < 1000) { - if (getUIFlag(0x19)) { + if (getUIFlag(UIFlags.Stash_is_open)) { delay(200); + return true; } delay(10); } } + + if (i > 1) { + Packet.flash(me.gid); + + if (stash) { + Pather.moveToUnit(stash); + } else { + this.move("stash"); + } + + telekinesis = false; + } } return false; }, getCorpse: function () { - var i, corpse; + var i, corpse, gid, + corpseList = [], + timer = getTickCount(); - for (i = 0; i < 3; i += 1) { - corpse = getUnit(0, me.name, 17); + // No equipped items - high chance of dying in last game, force retries + if (!me.getItem(-1, ItemModes.Item_equipped_self_or_merc)) { + for (i = 0; i < 5; i += 1) { + corpse = getUnit(UnitType.Player, me.name, PlayerModes.Dead); - if (corpse && getDistance(me, corpse) <= 20) { - while (copyUnit(corpse).x) { - Pather.moveToUnit(corpse, rand(-2, 2), rand(-2, 2)); - corpse.interact(); - delay(500); + if (corpse) { + break; } + + delay(500); + } + } else { + corpse = getUnit(UnitType.Player, me.name, PlayerModes.Dead); + } + + if (!corpse) { + return true; + } + + do { + 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()); + + while (corpseList.length > 0) { + if (me.dead) { + return false; + } + + gid = corpseList[0].gid; + + Pather.moveToUnit(corpseList[0]); + Misc.click(0, 0, corpseList[0]); + delay(500); + + if (getTickCount() - timer > 3000) { + Pather.moveTo(me.x + rand(-1, 1) * 4, me.y + rand(-1, 1) * 4); + } + + if (getTickCount() - timer > 30000) { + D2Bot.printToConsole("Failed to get corpse, stopping.", 9); + D2Bot.stop(); + } + + if (!getUnit(UnitType.Player, -1, -1, gid)) { + corpseList.shift(); } } - if (me.gametype === 0) { + if (me.gametype === GameType.Classic) { this.checkShard(); } @@ -1089,11 +1695,11 @@ MainLoop: checkShard: function () { var shard, check = {left: false, right: false}, - item = me.getItem("bld", 0); + item = me.getItem("bld", ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); if (item) { do { - if (item.location === 3 && item.quality === 7) { + if (item.location === ItemLocation.Inventory && item.quality === ItemQuality.Unique) { shard = copyUnit(item); break; @@ -1105,15 +1711,15 @@ MainLoop: return true; } - item = me.getItem(-1, 1); + item = me.getItem(-1, ItemModes.Item_equipped_self_or_merc); if (item) { do { - if (item.bodylocation === 4) { + if (item.bodylocation === ItemBodyLocation.RIGHT_ARM) { check.right = true; } - if (item.bodylocation === 5) { + if (item.bodylocation === ItemBodyLocation.LEFT_ARM) { check.left = true; } } while (item.getNext()); @@ -1123,14 +1729,14 @@ MainLoop: shard.toCursor(); while (me.itemoncursor) { - clickItem(0, 4); + clickItem(ClickType.Left_Click, ItemBodyLocation.RIGHT_ARM); delay(500); } } else if (!check.left) { shard.toCursor(); while (me.itemoncursor) { - clickItem(0, 5); + clickItem(ClickType.Left_Click, ItemBodyLocation.LEFT_ARM); delay(500); } } @@ -1138,27 +1744,30 @@ MainLoop: return true; }, - // TODO: Determine if this func can be avoided with better potion pickup code. clearBelt: function () { - var item = me.getItem(-1, 2), + while (!me.gameReady) { + delay(100); + } + + var item = me.getItem(-1, ItemLocation.Belt), clearList = []; if (item) { do { switch (item.itemType) { - case 76: // Healing + case NTItemTypes.healingpotion: // Healing if (Config.BeltColumn[item.x % 4] !== "hp") { clearList.push(copyUnit(item)); } break; - case 77: // Mana + case NTItemTypes.manapotion: // Mana if (Config.BeltColumn[item.x % 4] !== "mp") { clearList.push(copyUnit(item)); } break; - case 78: // Rejuvenation + case NTItemTypes.rejuvpotion: // Rejuvenation if (Config.BeltColumn[item.x % 4] !== "rv") { clearList.push(copyUnit(item)); } @@ -1176,34 +1785,100 @@ MainLoop: return true; }, + clearScrolls: function () { + var i, + items = me.getItems(); + + for (i = 0; !!items && i < items.length; i += 1) { + if (items[i].location === ItemLocation.Inventory && items[i].mode === ItemModes.Item_In_Inventory_Stash_Cube_Or_Store && items[i].itemType === NTItemTypes.scroll) { + if (getUIFlag(UIFlags.Shop_open_at_NPC) || (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(); + } + } + } + + return true; + }, + clearInventory: function () { - var i, items, - clearList = [], - item = me.getItem(-1, 0); + var i, col, result, item, beltSize, + items = []; + + this.checkQuestItems(); // only golden bird quest for now + + // Return potions to belt + item = me.getItem(-1, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); - // Potions (after death usually) if (item) { do { - if (item.location === 3) { - switch (item.itemType) { - case 76: // Healing - case 77: // Mana - clearList.push(copyUnit(item)); - break; - case 78: // Rejuv - if (Config.RejuvBuffer) { // TODO: Improve - break; + if (item.location === ItemLocation.Inventory && [NTItemTypes.healingpotion, NTItemTypes.manapotion, NTItemTypes.rejuvpotion].indexOf(item.itemType) > -1) { + items.push(copyUnit(item)); + } + } while (item.getNext()); + + beltSize = Storage.BeltSize(); + col = this.checkColumns(beltSize); + + // Sort from HP to RV + items.sort(function (a, b) { + return a.itemType - b.itemType; + }); + + while (items.length) { + item = items.shift(); + + 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(ClickType.Left_Click, i, 0, 2); + } + } else { + clickItem(ClickType.Shift_Left_Click, item.x, item.y, item.location); // Shift-click potion } - clearList.push(copyUnit(item)); - break; + delay(me.ping + 200); + + col = this.checkColumns(beltSize); } } + } + } + + // Cleanup remaining potions + item = me.getItem(-1, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store); + + if (item) { + items = [ + [], // array for hp + [] // array for mp + ]; + + do { + if (item.itemType === NTItemTypes.healingpotion) { + items[0].push(copyUnit(item)); + } + + if (item.itemType === NTItemTypes.manapotion) { + items[1].push(copyUnit(item)); + } } while (item.getNext()); - while (clearList.length > 0) { - clearList.shift().interact(); - delay(200); + // Cleanup healing potions + while (items[0].length > Config.HPBuffer) { + items[0].shift().interact(); + delay(200 + me.ping); + } + + // Cleanup mana potions + while (items[1].length > Config.MPBuffer) { + items[1].shift().interact(); + delay(200 + me.ping); } } @@ -1211,11 +1886,67 @@ MainLoop: items = Storage.Inventory.Compare(Config.Inventory); for (i = 0; !!items && i < items.length; i += 1) { - if ([18, 41, 78].indexOf(items[i].itemType) === -1 && Pickit.checkItem(items[i]) === 0 && !Cubing.keepItem(items[i]) && !Runewords.keepItem(items[i])) { - try { - items[i].drop(); - } catch (e) { - print(e); + if ([NTItemTypes.book, NTItemTypes.key, NTItemTypes.healingpotion, NTItemTypes.manapotion, NTItemTypes.rejuvpotion].indexOf(items[i].itemType) === -1 && // Don't drop tomes, keys or potions + // Keep some quest items + items[i].classid !== ItemClassIds.Scroll_Of_Inifuss && // Scroll of Inifuss + items[i].classid !== ItemClassIds.Key_To_The_Cairn_Stones && // Key to Cairn Stones + items[i].classid !== ItemClassIds.Horadric_Cube && // Horadric Cube + items[i].classid !== ItemClassIds.Staff_of_Kings && // Staff of Kings + items[i].classid !== ItemClassIds.Viper_Amulet && // Viper Amulet + items[i].classid !== ItemClassIds.Horadric_Staff && // Horadric Staff + items[i].classid !== ItemClassIds.Book_Of_Skill && // Book of Skill + items[i].classid !== ItemClassIds.Potion_of_Life && // Potion of Life + items[i].classid !== ItemClassIds.A_Jade_Figurine && // A Jade Figurine + items[i].classid !== ItemClassIds.The_Golden_Bird && // The Golden Bird + items[i].classid !== ItemClassIds.Lam_Esens_Tome && // Lam Esen's Tome + items[i].classid !== ItemClassIds.Khalims_Eye && // Khalim's Eye + items[i].classid !== ItemClassIds.Khalims_Heart && // Khalim's Heart + items[i].classid !== ItemClassIds.Khalims_Brain && // Khalim's Brain + items[i].classid !== ItemClassIds.Khalims_Flail && // Khalim's Flail + items[i].classid !== ItemClassIds.Khalims_Will && // Khalim's Will + items[i].classid !== ItemClassIds.Malahs_Potion && // Malah's Potion + items[i].classid !== ItemClassIds.Scroll_Of_Resistance && // Scroll of Resistance + // + (items[i].code !== ItemClassIds.Scroll_Of_Town_Portal || !!me.findItem(ItemClassIds.Tome_Of_Town_Portal, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory)) && // Don't throw scrolls if no tome is found (obsolete code?) + (items[i].code !== ItemClassIds.Scroll_Of_Identify || !!me.findItem(ItemClassIds.Tome_Of_Identify, ItemModes.Item_In_Inventory_Stash_Cube_Or_Store, ItemLocation.Inventory)) && // 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 + ) { + result = Pickit.checkItem(items[i]).result; + + if (!Item.autoEquipCheck(items[i])) { + result = 0; + } + + switch (result) { + case 0: // Drop item + if ((getUIFlag(UIFlags.Shop_open_at_NPC) || getUIFlag(UIFlags.npc_menu)) && (items[i].getItemCost(1) <= 1 || items[i].itemType === NTItemTypes.quest)) { // Quest items and such + me.cancel(); + delay(200); + } + + if (getUIFlag(UIFlags.Shop_open_at_NPC) || (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"); + items[i].drop(); + } + + 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; } } } @@ -1224,14 +1955,15 @@ MainLoop: }, act : [{}, {}, {}, {}, {}], + initialize: function () { //print("Initialize town " + me.act); switch (me.act) { case 1: - var fire, - wp = getPresetUnit(1, 2, 119), - fireUnit = getPresetUnit(1, 2, 39); + var fire, + wp = getPresetUnit(Areas.Act1.Rogue_Encampment, UnitType.Object, UniqueObjectIds.Waypoint_Portal), + fireUnit = getPresetUnit(Areas.Act1.Rogue_Encampment, UnitType.Object, UniqueObjectIds.RogueBonfire); if (!fireUnit) { return false; @@ -1263,10 +1995,10 @@ MainLoop: 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; @@ -1274,13 +2006,13 @@ MainLoop: case 3: this.act[2].spot = {}; this.act[2].spot.meshif = [5118, 5168]; - this.act[2].spot[NPC.Hratli] = [5223, 5048]; + this.act[2].spot[NPC.Hratli] = [5223, 5048, 5127, 5172]; this.act[2].spot[NPC.Ormus] = [5129, 5093]; this.act[2].spot[NPC.Asheara] = [5043, 5093]; this.act[2].spot[NPC.Alkor] = [5083, 5016]; this.act[2].spot.cain = [5148, 5066]; this.act[2].spot.stash = [5144, 5059]; - this.act[2].spot.portalspot = [5156, 5063]; + this.act[2].spot.portalspot = [5150, 5063]; this.act[2].spot.waypoint = [5158, 5050]; this.act[2].initialized = true; @@ -1299,7 +2031,7 @@ MainLoop: break; case 5: this.act[4].spot = {}; - this.act[4].spot.portalspot = [5097, 5024]; + this.act[4].spot.portalspot = [5098, 5019]; this.act[4].spot.stash = [5129, 5061]; this.act[4].spot[NPC.Larzuk] = [5141, 5045]; this.act[4].spot[NPC.Malah] = [5078, 5029]; @@ -1310,6 +2042,7 @@ MainLoop: this.act[4].spot.waypoint = [5113, 5068]; this.act[4].spot.nihlathak = [5071, 5111]; this.act[4].initialized = true; + break; } @@ -1317,77 +2050,137 @@ MainLoop: }, move: function (spot) { - if (!me.inTown) { // To prevent long trips if tp to town failed - throw new Error("Town.move: You're not in town!"); - } - - // TODO: Add character config variable for telekinesis - while (!me.idle) { - delay(40); + if (!me.inTown) { + this.goToTown(); } - var townSpot, temp, - useTK = me.classid === 1 && me.getSkill(43, 1) && ["stash", "portalspot", "waypoint"].indexOf(spot) > -1; + var i, path; if (!this.act[me.act - 1].initialized) { this.initialize(); } - if (typeof (this.act[me.act - 1].spot[spot]) === "object") { - //print("Moving to " + spot + " from " + me.x + " " + me.y); + // 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]; - townSpot = this.act[me.act - 1].spot[spot]; - } else { - //print("ÿc1Invalid town spot: " + spot); + for (i = 0; i < path.length; i += 2) { + Pather.walkTo(path[i], path[i + 1]); + } + + return true; + } + 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 === ClassID.Sorceress && this.telekinesis && me.getSkill(Skills.Sorceress.Telekinesis, 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; } - //temp = Pather.getNearestWalkable(townSpot[0], townSpot[1], 6, 1); + if (typeof (this.act[me.act - 1].spot[spot]) === "object") { + townSpot = this.act[me.act - 1].spot[spot]; + } else { + return false; + } - if (useTK) { - if (getDistance(me, townSpot[0], townSpot[1]) > 14) { - if (temp) { - Attack.getIntoPosition({x: temp[0], y: temp[1]}, 14, 0x4); - } + if (longRange) { + path = getPath(me.area, townSpot[0], townSpot[1], me.x, me.y, 1, 8); - Attack.getIntoPosition({x: townSpot[0], y: townSpot[1]}, 13, 0x4); + if (path && path[1]) { + townSpot = [path[1].x, path[1].y]; } - } else { - if (temp) { - Pather.moveTo(temp[0], temp[1], 3); + } + + for (i = 0; i < townSpot.length; i += 2) { + //print("moveToSpot: " + spot + " from " + me.x + ", " + me.y); + + if (getDistance(me, townSpot[i], townSpot[i + 1]) > 2) { + Pather.moveTo(townSpot[i], townSpot[i + 1], 3, false, true); } - Pather.moveTo(townSpot[0], townSpot[1], 3); - } + switch (spot) { + case "stash": + if (!!getUnit(UnitType.Object, UniqueObjectIds.Bank)) { + return true; + } - return true; - }, + break; + case "cain": + if (!!getUnit(UnitType.NPC, NPC.Cain)) { + return true; + } - goToTown: function (act) { - if (!act) { - act = me.act; + break; + case "palace": + if (!!getUnit(UnitType.NPC, "jerhyn")) { + return true; + } + + break; + case "portalspot": + case "sewers": + if (getDistance(me, townSpot[i], townSpot[i + 1]) < 10) { + return true; + } + + break; + case "waypoint": + if (!!getUnit(UnitType.Object, "waypoint")) { + return true; + } + + break; + default: + if (!!getUnit(UnitType.NPC, spot)) { + return true; + } + + break; + } } - var towns = [1, 40, 75, 103, 109]; + return false; + }, + + goToTown: function (act, wpmenu) { + var towns = [Areas.Act1.Rogue_Encampment, Areas.Act2.Lut_Gholein, Areas.Act3.Kurast_Docktown, Areas.Act4.The_Pandemonium_Fortress, Areas.Act5.Harrogath]; if (!me.inTown) { - if (!Pather.makePortal(true)) { + if (!Pather.makePortal()) { throw new Error("Town.goToTown: Failed to make TP"); } + + if (!Pather.usePortal(null, me.name)) { + throw new Error("Town.goToTown: Failed to take TP"); + } } - if (arguments.length < 1) { + if (act === undefined) { return true; } if (act < 1 || act > 5) { - throw new Error("Town.goToTown: Invalid act!"); + throw new Error("Town.goToTown: Invalid act"); } if (act !== me.act) { - if (!Pather.useWaypoint(towns[act - 1])) { - throw new Error("Town.goToTown: Failed to go to town"); + try { + Pather.useWaypoint(towns[act - 1], wpmenu); + } catch (WPError) { + throw new Error("Town.goToTown: Failed use WP"); } } @@ -1395,7 +2188,15 @@ MainLoop: }, visitTown: function () { - var preArea = me.area; + if (me.inTown) { + this.doChores(); + this.move("stash"); + + return true; + } + + var preArea = me.area, + preAct = me.act; try { // not an essential function -> handle thrown errors this.goToTown(); @@ -1404,10 +2205,15 @@ MainLoop: } this.doChores(); + + if (me.act !== preAct) { + this.goToTown(preAct); + } + this.move("portalspot"); - if (!Pather.usePortal(preArea, me.name)) { - return false; + if (!Pather.usePortal(preArea, me.name)) { // this part is essential + throw new Error("Town.visitTown: Failed to go back from town"); } if (Config.PublicMode) { diff --git a/d2bs/kolbot/libs/config/Amazon.js b/d2bs/kolbot/libs/config/Amazon.js index ed1eaec01..002e9923f 100644 --- a/d2bs/kolbot/libs/config/Amazon.js +++ b/d2bs/kolbot/libs/config/Amazon.js @@ -20,6 +20,7 @@ function LoadConfig() { Scripts.BattleOrders = false; Config.BattleOrders.Mode = 0; // 0 = give BO, 1 = get BO Config.BattleOrders.Wait = false; // Idle until the player that received BO leaves. + Config.BattleOrders.Getters = []; // List of players to wait for before casting Battle Orders (mode 0). All players must be in the same area as the BOer. // Team MF system Config.MFLeader = false; // Set to true if you have one or more MFHelpers. Opens TP and gives commands when doing normal MF runs. @@ -34,8 +35,10 @@ function LoadConfig() { Config.Mausoleum.ClearCrypt = false; Scripts.Rakanishu = false; Config.Rakanishu.KillGriswold = true; + Scripts.UndergroundPassage = false; Scripts.Coldcrow = false; Scripts.Tristram = false; + Config.Tristram.PortalLeech = false; // Set to true to open a portal for leechers. Scripts.Pit = false; Config.Pit.ClearPit1 = true; Scripts.Treehead = false; @@ -48,26 +51,31 @@ function LoadConfig() { // *** act 2 *** Scripts.Radament = false; + Scripts.Coldworm = false; + Config.Coldworm.KillBeetleburst = false; + Config.Coldworm.ClearMaggotLair = false; // Clear all 3 levels Scripts.AncientTunnels = false; + Config.AncientTunnels.OpenChest = false; // Open special chest in Lost City + Config.AncientTunnels.KillDarkElder = false; Scripts.Summoner = false; + Config.Summoner.FireEye = false; Scripts.Tombs = false; Scripts.Duriel = false; // *** act 3 *** Scripts.Stormtree = false; - Scripts.KurastChests = false; - Config.KurastChests.LowerKurast = true; - Config.KurastChests.Bazaar = false; - Config.KurastChests.Sewers1 = false; - Config.KurastChests.Sewers2 = false; Scripts.KurastTemples = false; Scripts.Icehawk = false; Scripts.Endugu = false; Scripts.Travincal = false; + Config.Travincal.PortalLeech = false; // Set to true to open a portal for leechers. Scripts.Mephisto = false; Config.Mephisto.MoatTrick = false; + Config.Mephisto.KillCouncil = false; + Config.Mephisto.TakeRedPortal = true; // *** act 4 *** + Scripts.OuterSteppes = false; Scripts.Izual = false; Scripts.Hephasto = false; Scripts.Vizier = false; // Intended for classic sorc, kills Vizier only. @@ -77,9 +85,12 @@ function LoadConfig() { Config.Diablo.SealWarning = "Leave the seals alone!"; 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; + Config.Pindleskin.UseWaypoint = false; Config.Pindleskin.KillNihlathak = true; Config.Pindleskin.ViperQuit = false; // End script if Tomb Vipers are found. Scripts.Nihlathak = false; @@ -89,59 +100,133 @@ function LoadConfig() { Config.Eldritch.KillShenk = true; Config.Eldritch.KillDacFarren = true; Scripts.Eyeback = false; + Scripts.SharpTooth = false; Scripts.ThreshSocket = false; Scripts.Abaddon = false; Scripts.Frozenstein = false; Config.Frozenstein.ClearFrozenRiver = true; Scripts.Bonesaw = false; + Config.Bonesaw.ClearDrifterCavern = false; Scripts.Snapchip = false; Config.Snapchip.ClearIcyCellar = true; + Scripts.Worldstone = false; Scripts.Baal = false; - Config.Baal.HotTPMsg = "Hot TP!"; - Config.Baal.SafeTPMsg = "TP safe!"; - Config.Baal.BaalMsg = "Baal"; - Config.Baal.DollQuit = false; // End script if Dolls (Undead Soul Killers) are found. + Config.Baal.HotTPMessage = "Hot TP!"; + Config.Baal.SafeTPMessage = "Safe TP!"; + Config.Baal.BaalMessage = "Baal!"; + Config.Baal.SoulQuit = false; // End script if Souls (Undead Soul Killers) are found. + Config.Baal.DollQuit = false; // End script if Dolls (Undead Stigyan Dolls) are found. + Config.Baal.KillBaal = true; // Kill Baal. Leaves game after wave 5 if false. /* ### leeching section ### * Unless stated otherwise, leader's character name isn't needed on order to run. * Don't use more scripts of the same type! (Run AutoBaal OR BaalHelper, not both) */ + 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.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; // Find shrine when hot tp message is sent. You can change messages in AutoBaal.js + 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 + Config.AutoBaal.LongRangeSupport = false; // Cast long distance skills from a safe spot Scripts.BaalHelper = false; + Config.BaalHelper.Wait = 120; // Seconds to wait for a runner to be in Throne Config.BaalHelper.KillNihlathak = false; // Kill Nihlathak before going to Throne Config.BaalHelper.FastChaos = false; // Kill Diablo before going to Throne Config.BaalHelper.DollQuit = false; // End script if Dolls (Undead Soul Killers) are found. + Config.BaalHelper.KillBaal = true; // Kill Baal. If set to false, you must configure Config.QuitList or the bot will wait indefinitely. + Config.BaalHelper.SkipTP = false; // Don't wait for a TP, go to WSK3 and wait for someone to go to throne. Anti PK measure. Scripts.Follower = false; // Script that follows a manually played leader around like a merc. For a list of commands, see Follower.js - Config.Follower.Leader = ""; // Leader's ingame name. This only applies to Follower script - - Config.QuitList = []; // List of character names to quit with. Example: Config.QuitList = ["MySorc", "MyDin"]; // *** special scripts *** - Scripts.Rusher = false; // Rush bot alpha version (no questing yet, only rushing), for a list of commands, see Rusher.js + Scripts.WPGetter = false; // Get missing waypoints + Scripts.GetKeys = false; // Hunt for T/H/D keys + Scripts.OrgTorch = false; + Config.OrgTorch.MakeTorch = true; // Convert organ sets to torches + Config.OrgTorch.WaitForKeys = true; // Enable Torch System to get keys from other profiles. See libs/TorchSystem.js for more info + 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. 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). + 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.Trigger = ".chant"; + Config.Enchant.Triggers = ["chant", "cows", "wps"]; // Chat commands for enchant, cow level and waypoint giving + Config.Enchant.GetLeg = false; // Get Wirt's Leg from Tristram. If set to false, it will check for the leg in town. + Config.Enchant.AutoChant = false; // Automatically enchant nearby players and their minions Config.Enchant.GameLength = 20; // Game length in minutes 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, alpha version - Config.ShopBot.ShopNPC = "Anya"; // Only Anya for now - // 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.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 = [Areas.Act1.Cave_Level_2, Areas.Act1.Underground_Passage_Level_2, Areas.Act1.Hole_Level_2, Areas.Act1.Pit_Level_2, Areas.Act1.Crypt, Areas.Act1.Mausoleum]; // List of act 1 areas to open chests in + Config.ChestMania.Act2 = [Areas.Act2.Stony_Tomb_Level_1, Areas.Act2.Stony_Tomb_Level_2, Areas.Act2.Ancient_Tunnels, Areas.Act2.Tal_Rashas_Tomb_1, Areas.Act2.Tal_Rashas_Tomb_2, Areas.Act2.Tal_Rashas_Tomb_3, Areas.Act2.Tal_Rashas_Tomb_4, Areas.Act2.Tal_Rashas_Tomb_5, Areas.Act2.Tal_Rashas_Tomb_6, Areas.Act2.Tal_Rashas_Tomb_7]; // List of act 2 areas to open chests in + Config.ChestMania.Act3 = [Areas.Act3.Lower_Kurast, Areas.Act3.Kurast_Bazaar, Areas.Act3.Upper_Kurast, Areas.Act3.A3_Sewers_Level_1, Areas.Act3.A3_Sewers_Level_2, Areas.Act3.Spider_Cave, Areas.Act3.Spider_Cavern, Areas.Act3.Swampy_Pit_Level_3]; // List of act 3 areas to open chests in + Config.ChestMania.Act4 = []; // List of act 4 areas to open chests in + Config.ChestMania.Act5 = [Areas.Act5.Glacial_Trail, Areas.Act5.Drifter_Cavern, Areas.Act5.Icy_Cellar, Areas.Act5.Abaddon, Areas.Act5.Pit_Of_Acheron, Areas.Act5.Infernal_Pit]; // List of act 5 areas to open chests in + 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 (Enums Example: [Areas.Act1.Cave_Level_2, Areas.Act3.Kurast_Bazaar, Areas.Act5.Pit_Of_Acheron]; Ref. at https://pastebin.com/pRFkqDzb) + + + // *** Guest scripts *** + + // Baal Assistant by YourGreatestMember + Scripts.BaalAssistant = false; // Used to leech or help in baal runs. + Config.BaalAssistant.Wait = 120; // Seconds to wait for a runner to be in the throne / portal wait / safe TP wait / hot TP wait... + Config.BaalAssistant.KillNihlathak = false; // Kill Nihlathak before going to Throne + Config.BaalAssistant.FastChaos = false; // Kill Diablo before going to Throne + Config.BaalAssistant.Helper = true; // Set to true to help attack, set false to to leech. + Config.BaalAssistant.GetShrine = false; // Set to true to get a experience shrine at the start of the run. + Config.BaalAssistant.GetShrineWaitForHotTP = false; // Set to true to get a experience shrine after leader shouts the hot tp message as defined in Config.BaalAssistant.HotTPMessage + Config.BaalAssistant.SkipTP = false; // Set to true to enable the helper to skip the TP and teleport down to the throne room. + Config.BaalAssistant.WaitForSafeTP = false; // Set to true to wait for a safe TP message (defined in SafeTPMessage) + Config.BaalAssistant.DollQuit = false; // Quit on dolls. (Hardcore players?) + Config.BaalAssistant.SoulQuit = false; // Quit on Souls. (Hardcore players?) + Config.BaalAssistant.KillBaal = true; // Set to true to kill baal, if you set to false you MUST configure Config.QuitList or Config.BaalAssistant.NextGameMessage or the bot will wait indefinitely. + Config.BaalAssistant.HotTPMessage = ["Hot"]; // Configure safe TP messages. + Config.BaalAssistant.SafeTPMessage = ["Safe", "Clear"]; // Configure safe TP messages. + Config.BaalAssistant.BaalMessage = ["Baal"]; // Configure baal messages, this is a precautionary measure. + Config.BaalAssistant.NextGameMessage = ["Next Game", "Next", "New Game"]; // Next Game message, this is a precautionary quit command, Reccomended setting up: Config.QuitList // Town settings Config.HealHP = 50; // Go to a healer if under designated percent of life. Config.HealMP = 0; // Go to a healer if under designated percent of mana. + Config.HealStatus = false; // Go to a healer if poisoned or cursed Config.UseMerc = true; // Use merc. This is ignored and always false in d2classic. Config.MercWatch = false; // Instant merc revive during battle. @@ -152,6 +237,8 @@ function LoadConfig() { Config.UseRejuvMP = 0; // Drink a rejuvenation potion if mana is under designated percent. Config.UseMercHP = 75; // Give a healing potion to your merc if his/her life is under designated percent. Config.UseMercRejuv = 0; // Give a rejuvenation potion to your merc if his/her life is under designated percent. + Config.HPBuffer = 0; // Number of healing potions to keep in inventory. + Config.MPBuffer = 0; // Number of mana potions to keep in inventory. Config.RejuvBuffer = 0; // Number of rejuvenation potions to keep in inventory. // Chicken settings @@ -191,87 +278,156 @@ function LoadConfig() { Config.MinColumn[2] = 0; Config.MinColumn[3] = 0; - // Pickit config - Config.PickitFiles.push("kolton.nip"); // Pickit filenames in /pickit/ folder + // Pickit config. Default folder is kolbot/pickit. + Config.PickitFiles.push("kolton.nip"); Config.PickitFiles.push("LLD.nip"); Config.PickRange = 40; // Pick radius Config.FastPick = false; // Check and pick items between attacks + // 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. 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. + Config.RepairPercent = 40; // Durability percent of any equipped item that will trigger repairs. // Gambling config Config.Gamble = false; 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 - - // Cubing config. All recipes are available in Templates/Cubing.txt + + // 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. 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. - // All ingredients will be auto-picked, for classids check libs/NTItemAlias.dbl - 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 + // Ingredients for the following recipes will be auto-picked, for classids check libs/NTItemAlias.dbl + + //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]); // 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, "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, "Diadem"]); // Reroll magic Diadem + //Config.Recipes.push([Recipe.Reroll.Magic, "Grand Charm"]); // Reroll magic Grand Charm (ilvl 91+) - 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.Glove, 452]); // Craft Hit Power Vambraces + //Config.Recipes.push([Recipe.Reroll.Rare, "Diadem"]); // Reroll rare Diadem - Config.Recipes.push([Recipe.Reroll.Magic, 421]); // Reroll magic Diadem - Config.Recipes.push([Recipe.Reroll.Rare, 421]); // 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, "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 - // Base item must be in the pickit, rest is auto-picked - Config.Recipes.push([Recipe.Socket.Weapon, 255]); // Socket Thresher - Config.Recipes.push([Recipe.Socket.Weapon, 256]); // Socket Cryptic Axe - Config.Recipes.push([Recipe.Socket.Armor, 442]); // Socket Sacred Armor - Config.Recipes.push([Recipe.Socket.Armor, 443]); // Socket Archon Plate + //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 - * !!!NOTE!!! enhanced damage and enhanced defense on runewords are broken in the core right now * 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.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"); + //Config.KeepRunewords.push("[type] == shield || [type] == auricshields # [fcr] == 35"); - // General config - Config.PublicMode = 0; // 1 = invite, 2 = accept, 0 = disable - Config.LastMessage = ""; // Message to say at the end of the run. + // Public game options + + // If Config.Leader is set, the bot will only accept invites from leader. If Config.PublicMode is not 0, Baal and Diablo script will open Town Portals. + Config.PublicMode = 0; // 1 = invite and accept, 2 = accept only, 3 = invite only, 0 = disable + // Party message settings. Each setting represents an array of messages that will be randomly chosen. + // $name, $level, $class and $killer are replaced by the player's name, level, class and killer + Config.Greetings = []; // Example: ["Hello, $name (level $level $class)"] + 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.MinGameTime = 60; // Min game time in seconds. Bot will stay in game if the run is completed before. + 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. 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. + + // Shrine Scanner - scan for shrines while moving. + // Put the shrine types in order of priority (from highest to lowest). For a list of types, see sdk/shrines.txt + Config.ScanShrines = []; // Available Shrines: [Shrines.refilling, Shrines.health, Shrines.mana, Shrines.experience, Shrines.skill, Shrines.resist_lightning, Shrines.resist_fire, Shrines.armor, Shrines.combat, Shrines.resist_cold, Shrines.resist_poison, Shrines.mana_recharge, Shrines.stamina, Shrines.portal, Shrines.gem, Shrines.monster, Shrines.exploding, Shrines.poison]; + + // MF Switch + Config.MFSwitchPercent = 0; // Boss life % to switch weapons at. Set to 0 to disable. + Config.MFSwitch = 0; // MF weapon slot: 0 = slot I, 1 = slot II + + // Fastmod config + Config.FCR = 0; // 0 - disable, 1 to 255 - set value of faster cast rate + Config.FHR = 0; // 0 - disable, 1 to 255 - set value of faster hit recovery + 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 Config.HostileAction = 0; // 0 - quit immediately, 1 - quit when hostile player is sighted, 2 - attack hostile + Config.TownOnHostile = false; // Go to town instead of quitting when HostileAction is 0 or 1 + Config.RandomPrecast = false; // Anti-PK measure, only supported in Baal and BaalHelper and BaalAssisstant at the moment. + Config.ViperCheck = false; // Quit if revived Tomb Vipers are sighted // DClone config 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". @@ -286,6 +442,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 + * Example of Enums using: Config.AttackSkill[1] = Skills.Paladin.Blessed_Hammer; For Reference see https://pastebin.com/K7qCZw81 */ Config.AttackSkill[0] = -1; // Preattack skill. Config.AttackSkill[1] = -1; // Primary skill to bosses. @@ -295,10 +452,41 @@ function LoadConfig() { Config.AttackSkill[5] = -1; // Secondary skill if monster is immune to primary. Config.AttackSkill[6] = -1; // Secondary untimed skill if monster is immune to primary untimed. + // Low mana skills - these will be used if main skills can't be cast. + 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. 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 + // Wereform setup. Make sure you read Templates/Attacks.txt for attack skill format. + Config.Wereform = false; // 0 / false - don't shapeshift, 1 / "Werewolf" - change to werewolf, 2 / "Werebear" - change to werebear + // Class specific config + Config.LightningFuryDelay = 10; // Lightning fury interval in seconds. LF is treated as timed skill. Config.SummonValkyrie = true; // Summon Valkyrie + + + // AutoBuild System ( See /d2bs/kolbot/libs/config/Builds/README.txt for instructions ) + Config.AutoBuild.Enabled = false; // This will enable or disable the AutoBuild system + + Config.AutoBuild.Template = "BuildName"; // The name of the build associated with an existing + // template filename located in libs/config/Builds/ + + Config.AutoBuild.Verbose = true; // Allows script to print messages in console + Config.AutoBuild.DebugMode = true; // Debug mode prints a little more information to console and + // logs activity to /logs/AutoBuild.CharacterName._MM_DD_YYYY.log + // It automatically enables Config.AutoBuild.Verbose } \ No newline at end of file diff --git a/d2bs/kolbot/libs/config/Assassin.js b/d2bs/kolbot/libs/config/Assassin.js index 5dabe3dff..bbaefb4ac 100644 --- a/d2bs/kolbot/libs/config/Assassin.js +++ b/d2bs/kolbot/libs/config/Assassin.js @@ -20,6 +20,7 @@ function LoadConfig() { Scripts.BattleOrders = false; Config.BattleOrders.Mode = 0; // 0 = give BO, 1 = get BO Config.BattleOrders.Wait = false; // Idle until the player that received BO leaves. + Config.BattleOrders.Getters = []; // List of players to wait for before casting Battle Orders (mode 0). All players must be in the same area as the BOer. // Team MF system Config.MFLeader = false; // Set to true if you have one or more MFHelpers. Opens TP and gives commands when doing normal MF runs. @@ -34,8 +35,10 @@ function LoadConfig() { Config.Mausoleum.ClearCrypt = false; Scripts.Rakanishu = false; Config.Rakanishu.KillGriswold = true; + Scripts.UndergroundPassage = false; Scripts.Coldcrow = false; Scripts.Tristram = false; + Config.Tristram.PortalLeech = false; // Set to true to open a portal for leechers. Scripts.Pit = false; Config.Pit.ClearPit1 = true; Scripts.Treehead = false; @@ -48,26 +51,31 @@ function LoadConfig() { // *** act 2 *** Scripts.Radament = false; + Scripts.Coldworm = false; + Config.Coldworm.KillBeetleburst = false; + Config.Coldworm.ClearMaggotLair = false; // Clear all 3 levels Scripts.AncientTunnels = false; + Config.AncientTunnels.OpenChest = false; // Open special chest in Lost City + Config.AncientTunnels.KillDarkElder = false; Scripts.Summoner = false; + Config.Summoner.FireEye = false; Scripts.Tombs = false; Scripts.Duriel = false; // *** act 3 *** Scripts.Stormtree = false; - Scripts.KurastChests = false; - Config.KurastChests.LowerKurast = true; - Config.KurastChests.Bazaar = false; - Config.KurastChests.Sewers1 = false; - Config.KurastChests.Sewers2 = false; Scripts.KurastTemples = false; Scripts.Icehawk = false; Scripts.Endugu = false; Scripts.Travincal = false; + Config.Travincal.PortalLeech = false; // Set to true to open a portal for leechers. Scripts.Mephisto = false; Config.Mephisto.MoatTrick = false; + Config.Mephisto.KillCouncil = false; + Config.Mephisto.TakeRedPortal = true; // *** act 4 *** + Scripts.OuterSteppes = false; Scripts.Izual = false; Scripts.Hephasto = false; Scripts.Vizier = false; // Intended for classic sorc, kills Vizier only. @@ -77,9 +85,12 @@ function LoadConfig() { Config.Diablo.SealWarning = "Leave the seals alone!"; 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; + Config.Pindleskin.UseWaypoint = false; Config.Pindleskin.KillNihlathak = true; Config.Pindleskin.ViperQuit = false; // End script if Tomb Vipers are found. Scripts.Nihlathak = false; @@ -89,59 +100,133 @@ function LoadConfig() { Config.Eldritch.KillShenk = true; Config.Eldritch.KillDacFarren = true; Scripts.Eyeback = false; + Scripts.SharpTooth = false; Scripts.ThreshSocket = false; Scripts.Abaddon = false; Scripts.Frozenstein = false; Config.Frozenstein.ClearFrozenRiver = true; Scripts.Bonesaw = false; + Config.Bonesaw.ClearDrifterCavern = false; Scripts.Snapchip = false; Config.Snapchip.ClearIcyCellar = true; + Scripts.Worldstone = false; Scripts.Baal = false; - Config.Baal.HotTPMsg = "Hot TP!"; - Config.Baal.SafeTPMsg = "TP safe!"; - Config.Baal.BaalMsg = "Baal"; - Config.Baal.DollQuit = false; // End script if Dolls (Undead Soul Killers) are found. + Config.Baal.HotTPMessage = "Hot TP!"; + Config.Baal.SafeTPMessage = "Safe TP!"; + Config.Baal.BaalMessage = "Baal!"; + Config.Baal.SoulQuit = false; // End script if Souls (Undead Soul Killers) are found. + Config.Baal.DollQuit = false; // End script if Dolls (Undead Stigyan Dolls) are found. + Config.Baal.KillBaal = true; // Kill Baal. Leaves game after wave 5 if false. /* ### leeching section ### * Unless stated otherwise, leader's character name isn't needed on order to run. * Don't use more scripts of the same type! (Run AutoBaal OR BaalHelper, not both) */ + 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.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; // Find shrine when hot tp message is sent. You can change messages in AutoBaal.js + 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 + Config.AutoBaal.LongRangeSupport = false; // Cast long distance skills from a safe spot Scripts.BaalHelper = false; + Config.BaalHelper.Wait = 120; // Seconds to wait for a runner to be in Throne Config.BaalHelper.KillNihlathak = false; // Kill Nihlathak before going to Throne Config.BaalHelper.FastChaos = false; // Kill Diablo before going to Throne Config.BaalHelper.DollQuit = false; // End script if Dolls (Undead Soul Killers) are found. + Config.BaalHelper.KillBaal = true; // Kill Baal. If set to false, you must configure Config.QuitList or the bot will wait indefinitely. + Config.BaalHelper.SkipTP = false; // Don't wait for a TP, go to WSK3 and wait for someone to go to throne. Anti PK measure. Scripts.Follower = false; // Script that follows a manually played leader around like a merc. For a list of commands, see Follower.js - Config.Follower.Leader = ""; // Leader's ingame name. This only applies to Follower script - - Config.QuitList = []; // List of character names to quit with. Example: Config.QuitList = ["MySorc", "MyDin"]; // *** special scripts *** - Scripts.Rusher = false; // Rush bot alpha version (no questing yet, only rushing), for a list of commands, see Rusher.js + Scripts.WPGetter = false; // Get missing waypoints + Scripts.GetKeys = false; // Hunt for T/H/D keys + Scripts.OrgTorch = false; + Config.OrgTorch.MakeTorch = true; // Convert organ sets to torches + Config.OrgTorch.WaitForKeys = true; // Enable Torch System to get keys from other profiles. See libs/TorchSystem.js for more info + 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. 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). + 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.Trigger = ".chant"; + Config.Enchant.Triggers = ["chant", "cows", "wps"]; // Chat commands for enchant, cow level and waypoint giving + Config.Enchant.GetLeg = false; // Get Wirt's Leg from Tristram. If set to false, it will check for the leg in town. + Config.Enchant.AutoChant = false; // Automatically enchant nearby players and their minions Config.Enchant.GameLength = 20; // Game length in minutes 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, alpha version - Config.ShopBot.ShopNPC = "Anya"; // Only Anya for now - // 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.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 = [Areas.Act1.Cave_Level_2, Areas.Act1.Underground_Passage_Level_2, Areas.Act1.Hole_Level_2, Areas.Act1.Pit_Level_2, Areas.Act1.Crypt, Areas.Act1.Mausoleum]; // List of act 1 areas to open chests in + Config.ChestMania.Act2 = [Areas.Act2.Stony_Tomb_Level_1, Areas.Act2.Stony_Tomb_Level_2, Areas.Act2.Ancient_Tunnels, Areas.Act2.Tal_Rashas_Tomb_1, Areas.Act2.Tal_Rashas_Tomb_2, Areas.Act2.Tal_Rashas_Tomb_3, Areas.Act2.Tal_Rashas_Tomb_4, Areas.Act2.Tal_Rashas_Tomb_5, Areas.Act2.Tal_Rashas_Tomb_6, Areas.Act2.Tal_Rashas_Tomb_7]; // List of act 2 areas to open chests in + Config.ChestMania.Act3 = [Areas.Act3.Lower_Kurast, Areas.Act3.Kurast_Bazaar, Areas.Act3.Upper_Kurast, Areas.Act3.A3_Sewers_Level_1, Areas.Act3.A3_Sewers_Level_2, Areas.Act3.Spider_Cave, Areas.Act3.Spider_Cavern, Areas.Act3.Swampy_Pit_Level_3]; // List of act 3 areas to open chests in + Config.ChestMania.Act4 = []; // List of act 4 areas to open chests in + Config.ChestMania.Act5 = [Areas.Act5.Glacial_Trail, Areas.Act5.Drifter_Cavern, Areas.Act5.Icy_Cellar, Areas.Act5.Abaddon, Areas.Act5.Pit_Of_Acheron, Areas.Act5.Infernal_Pit]; // List of act 5 areas to open chests in + 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 (Enums Example: [Areas.Act1.Cave_Level_2, Areas.Act3.Kurast_Bazaar, Areas.Act5.Pit_Of_Acheron]; Ref. at https://pastebin.com/pRFkqDzb) + + + // *** Guest scripts *** + + // Baal Assistant by YourGreatestMember + Scripts.BaalAssistant = false; // Used to leech or help in baal runs. + Config.BaalAssistant.Wait = 120; // Seconds to wait for a runner to be in the throne / portal wait / safe TP wait / hot TP wait... + Config.BaalAssistant.KillNihlathak = false; // Kill Nihlathak before going to Throne + Config.BaalAssistant.FastChaos = false; // Kill Diablo before going to Throne + Config.BaalAssistant.Helper = true; // Set to true to help attack, set false to to leech. + Config.BaalAssistant.GetShrine = false; // Set to true to get a experience shrine at the start of the run. + Config.BaalAssistant.GetShrineWaitForHotTP = false; // Set to true to get a experience shrine after leader shouts the hot tp message as defined in Config.BaalAssistant.HotTPMessage + Config.BaalAssistant.SkipTP = false; // Set to true to enable the helper to skip the TP and teleport down to the throne room. + Config.BaalAssistant.WaitForSafeTP = false; // Set to true to wait for a safe TP message (defined in SafeTPMessage) + Config.BaalAssistant.DollQuit = false; // Quit on dolls. (Hardcore players?) + Config.BaalAssistant.SoulQuit = false; // Quit on Souls. (Hardcore players?) + Config.BaalAssistant.KillBaal = true; // Set to true to kill baal, if you set to false you MUST configure Config.QuitList or Config.BaalAssistant.NextGameMessage or the bot will wait indefinitely. + Config.BaalAssistant.HotTPMessage = ["Hot"]; // Configure safe TP messages. + Config.BaalAssistant.SafeTPMessage = ["Safe", "Clear"]; // Configure safe TP messages. + Config.BaalAssistant.BaalMessage = ["Baal"]; // Configure baal messages, this is a precautionary measure. + Config.BaalAssistant.NextGameMessage = ["Next Game", "Next", "New Game"]; // Next Game message, this is a precautionary quit command, Reccomended setting up: Config.QuitList // Town settings Config.HealHP = 50; // Go to a healer if under designated percent of life. Config.HealMP = 0; // Go to a healer if under designated percent of mana. + Config.HealStatus = false; // Go to a healer if poisoned or cursed Config.UseMerc = true; // Use merc. This is ignored and always false in d2classic. Config.MercWatch = false; // Instant merc revive during battle. @@ -152,6 +237,8 @@ function LoadConfig() { Config.UseRejuvMP = 0; // Drink a rejuvenation potion if mana is under designated percent. Config.UseMercHP = 75; // Give a healing potion to your merc if his/her life is under designated percent. Config.UseMercRejuv = 0; // Give a rejuvenation potion to your merc if his/her life is under designated percent. + Config.HPBuffer = 0; // Number of healing potions to keep in inventory. + Config.MPBuffer = 0; // Number of mana potions to keep in inventory. Config.RejuvBuffer = 0; // Number of rejuvenation potions to keep in inventory. // Chicken settings @@ -191,87 +278,156 @@ function LoadConfig() { Config.MinColumn[2] = 0; Config.MinColumn[3] = 0; - // Pickit config - Config.PickitFiles.push("kolton.nip"); // Pickit filenames in /pickit/ folder + // Pickit config. Default folder is kolbot/pickit. + Config.PickitFiles.push("kolton.nip"); Config.PickitFiles.push("LLD.nip"); Config.PickRange = 40; // Pick radius Config.FastPick = false; // Check and pick items between attacks + // 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. 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. + Config.RepairPercent = 40; // Durability percent of any equipped item that will trigger repairs. // Gambling config Config.Gamble = false; 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 - - // Cubing config. All recipes are available in Templates/Cubing.txt + + // 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. 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. - // All ingredients will be auto-picked, for classids check libs/NTItemAlias.dbl - 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 + // Ingredients for the following recipes will be auto-picked, for classids check libs/NTItemAlias.dbl + + //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]); // 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.Glove, 452]); // Craft Hit Power Vambraces + //Config.Recipes.push([Recipe.Caster.Amulet]); // Craft Caster Amulet + //Config.Recipes.push([Recipe.Blood.Ring]); // Craft Blood Ring + //Config.Recipes.push([Recipe.Blood.Helm, "Armet"]); // Craft Blood Armet + //Config.Recipes.push([Recipe.HitPower.Gloves, "Vambraces"]); // Craft Hit Power Vambraces - Config.Recipes.push([Recipe.Reroll.Magic, 421]); // Reroll magic Diadem - Config.Recipes.push([Recipe.Reroll.Rare, 421]); // Reroll rare Diadem + // The gems not used by other recipes will be used for magic item rerolling. + + //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, "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, "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 - // Base item must be in the pickit, rest is auto-picked - Config.Recipes.push([Recipe.Socket.Weapon, 255]); // Socket Thresher - Config.Recipes.push([Recipe.Socket.Weapon, 256]); // Socket Cryptic Axe - Config.Recipes.push([Recipe.Socket.Armor, 442]); // Socket Sacred Armor - Config.Recipes.push([Recipe.Socket.Armor, 443]); // Socket Archon Plate + //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 - * !!!NOTE!!! enhanced damage and enhanced defense on runewords are broken in the core right now * 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.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"); + //Config.KeepRunewords.push("[type] == shield || [type] == auricshields # [fcr] == 35"); - // General config - Config.PublicMode = 0; // 1 = invite, 2 = accept, 0 = disable - Config.LastMessage = ""; // Message to say at the end of the run. + // Public game options + + // If Config.Leader is set, the bot will only accept invites from leader. If Config.PublicMode is not 0, Baal and Diablo script will open Town Portals. + Config.PublicMode = 0; // 1 = invite and accept, 2 = accept only, 3 = invite only, 0 = disable + // Party message settings. Each setting represents an array of messages that will be randomly chosen. + // $name, $level, $class and $killer are replaced by the player's name, level, class and killer + Config.Greetings = []; // Example: ["Hello, $name (level $level $class)"] + 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.MinGameTime = 60; // Min game time in seconds. Bot will stay in game if the run is completed before. + 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. 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. + + // Shrine Scanner - scan for shrines while moving. + // Put the shrine types in order of priority (from highest to lowest). For a list of types, see sdk/shrines.txt + Config.ScanShrines = []; // Available Shrines: [Shrines.refilling, Shrines.health, Shrines.mana, Shrines.experience, Shrines.skill, Shrines.resist_lightning, Shrines.resist_fire, Shrines.armor, Shrines.combat, Shrines.resist_cold, Shrines.resist_poison, Shrines.mana_recharge, Shrines.stamina, Shrines.portal, Shrines.gem, Shrines.monster, Shrines.exploding, Shrines.poison]; + + // MF Switch + Config.MFSwitchPercent = 0; // Boss life % to switch weapons at. Set to 0 to disable. + Config.MFSwitch = 0; // MF weapon slot: 0 = slot I, 1 = slot II + + // Fastmod config + Config.FCR = 0; // 0 - disable, 1 to 255 - set value of faster cast rate + Config.FHR = 0; // 0 - disable, 1 to 255 - set value of faster hit recovery + 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 Config.HostileAction = 0; // 0 - quit immediately, 1 - quit when hostile player is sighted, 2 - attack hostile + Config.TownOnHostile = false; // Go to town instead of quitting when HostileAction is 0 or 1 + Config.RandomPrecast = false; // Anti-PK measure, only supported in Baal and BaalHelper and BaalAssisstant at the moment. + Config.ViperCheck = false; // Quit if revived Tomb Vipers are sighted // DClone config 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". @@ -286,7 +442,8 @@ 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 + * Example of Enums using: Config.AttackSkill[1] = Skills.Paladin.Blessed_Hammer; For Reference see https://pastebin.com/K7qCZw81 */ Config.AttackSkill[0] = -1; // Preattack skill. Config.AttackSkill[1] = -1; // Primary skill to bosses. @@ -296,9 +453,27 @@ function LoadConfig() { Config.AttackSkill[5] = -1; // Secondary skill if monster is immune to primary. Config.AttackSkill[6] = -1; // Secondary untimed skill if monster is immune to primary untimed. + // Low mana skills - these will be used if main skills can't be cast. + 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. 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 + // Wereform setup. Make sure you read Templates/Attacks.txt for attack skill format. + Config.Wereform = false; // 0 / false - don't shapeshift, 1 / "Werewolf" - change to werewolf, 2 / "Werebear" - change to werebear + // Class specific config Config.UseTraps = true; // Set to true to use traps Config.Traps = [271, 271, 271, 276, 276]; // Skill IDs for traps to be cast on all mosters except act bosses. @@ -309,4 +484,16 @@ function LoadConfig() { Config.UseBoS = false; // Set to true to use Burst of Speed prebuff. TODO: Casting in town + UseFade compatibility Config.UseVenom = false; // Set to true to use Venom prebuff. Set to false if you don't have the skill and have Arachnid Mesh - it will cause connection drop otherwise. Config.UseCloakofShadows = true; // Set to true to use Cloak of Shadows while fighting. Useful for blinding regular monsters/minions. + + + // AutoBuild System ( See /d2bs/kolbot/libs/config/Builds/README.txt for instructions ) + Config.AutoBuild.Enabled = false; // This will enable or disable the AutoBuild system + + Config.AutoBuild.Template = "BuildName"; // The name of the build associated with an existing + // template filename located in libs/config/Builds/ + + Config.AutoBuild.Verbose = true; // Allows script to print messages in console + Config.AutoBuild.DebugMode = true; // Debug mode prints a little more information to console and + // logs activity to /logs/AutoBuild.CharacterName._MM_DD_YYYY.log + // It automatically enables Config.AutoBuild.Verbose } \ No newline at end of file diff --git a/d2bs/kolbot/libs/config/Barbarian.js b/d2bs/kolbot/libs/config/Barbarian.js index 7c6dd5c49..48b59cc7e 100644 --- a/d2bs/kolbot/libs/config/Barbarian.js +++ b/d2bs/kolbot/libs/config/Barbarian.js @@ -6,7 +6,7 @@ * !!!Never comment out something you're not sure about, set it to false or disable as noted in description if you don't want to use it. * true and false are case sensitive. Good: Config.SomeVar = true; Bad: Config.SomeVar = True; */ - + function LoadConfig() { /* Sequence config * Set to true if you want to run it, set to false if not. @@ -20,6 +20,7 @@ function LoadConfig() { Scripts.BattleOrders = false; Config.BattleOrders.Mode = 0; // 0 = give BO, 1 = get BO Config.BattleOrders.Wait = false; // Idle until the player that received BO leaves. + Config.BattleOrders.Getters = []; // List of players to wait for before casting Battle Orders (mode 0). All players must be in the same area as the BOer. // Team MF system Config.MFLeader = false; // Set to true if you have one or more MFHelpers. Opens TP and gives commands when doing normal MF runs. @@ -34,8 +35,10 @@ function LoadConfig() { Config.Mausoleum.ClearCrypt = false; Scripts.Rakanishu = false; Config.Rakanishu.KillGriswold = true; + Scripts.UndergroundPassage = false; Scripts.Coldcrow = false; Scripts.Tristram = false; + Config.Tristram.PortalLeech = false; // Set to true to open a portal for leechers. Scripts.Pit = false; Config.Pit.ClearPit1 = true; Scripts.Treehead = false; @@ -48,26 +51,31 @@ function LoadConfig() { // *** act 2 *** Scripts.Radament = false; + Scripts.Coldworm = false; + Config.Coldworm.KillBeetleburst = false; + Config.Coldworm.ClearMaggotLair = false; // Clear all 3 levels Scripts.AncientTunnels = false; + Config.AncientTunnels.OpenChest = false; // Open special chest in Lost City + Config.AncientTunnels.KillDarkElder = false; Scripts.Summoner = false; + Config.Summoner.FireEye = false; Scripts.Tombs = false; Scripts.Duriel = false; // *** act 3 *** Scripts.Stormtree = false; - Scripts.KurastChests = false; - Config.KurastChests.LowerKurast = true; - Config.KurastChests.Bazaar = false; - Config.KurastChests.Sewers1 = false; - Config.KurastChests.Sewers2 = false; Scripts.KurastTemples = false; Scripts.Icehawk = false; Scripts.Endugu = false; Scripts.Travincal = false; + Config.Travincal.PortalLeech = false; // Set to true to open a portal for leechers. Scripts.Mephisto = false; Config.Mephisto.MoatTrick = false; + Config.Mephisto.KillCouncil = false; + Config.Mephisto.TakeRedPortal = true; // *** act 4 *** + Scripts.OuterSteppes = false; Scripts.Izual = false; Scripts.Hephasto = false; Scripts.Vizier = false; // Intended for classic sorc, kills Vizier only. @@ -77,9 +85,12 @@ function LoadConfig() { Config.Diablo.SealWarning = "Leave the seals alone!"; 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; + Config.Pindleskin.UseWaypoint = false; Config.Pindleskin.KillNihlathak = true; Config.Pindleskin.ViperQuit = false; // End script if Tomb Vipers are found. Scripts.Nihlathak = false; @@ -89,59 +100,133 @@ function LoadConfig() { Config.Eldritch.KillShenk = true; Config.Eldritch.KillDacFarren = true; Scripts.Eyeback = false; + Scripts.SharpTooth = false; Scripts.ThreshSocket = false; Scripts.Abaddon = false; Scripts.Frozenstein = false; Config.Frozenstein.ClearFrozenRiver = true; Scripts.Bonesaw = false; + Config.Bonesaw.ClearDrifterCavern = false; Scripts.Snapchip = false; Config.Snapchip.ClearIcyCellar = true; + Scripts.Worldstone = false; Scripts.Baal = false; - Config.Baal.HotTPMsg = "Hot TP!"; - Config.Baal.SafeTPMsg = "TP safe!"; - Config.Baal.BaalMsg = "Baal"; - Config.Baal.DollQuit = false; // End script if Dolls (Undead Soul Killers) are found. + Config.Baal.HotTPMessage = "Hot TP!"; + Config.Baal.SafeTPMessage = "Safe TP!"; + Config.Baal.BaalMessage = "Baal!"; + Config.Baal.SoulQuit = false; // End script if Souls (Undead Soul Killers) are found. + Config.Baal.DollQuit = false; // End script if Dolls (Undead Stigyan Dolls) are found. + Config.Baal.KillBaal = true; // Kill Baal. Leaves game after wave 5 if false. /* ### leeching section ### * Unless stated otherwise, leader's character name isn't needed on order to run. * Don't use more scripts of the same type! (Run AutoBaal OR BaalHelper, not both) */ + 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.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; // Find shrine when hot tp message is sent. You can change messages in AutoBaal.js + 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 + Config.AutoBaal.LongRangeSupport = false; // Cast long distance skills from a safe spot Scripts.BaalHelper = false; + Config.BaalHelper.Wait = 120; // Seconds to wait for a runner to be in Throne Config.BaalHelper.KillNihlathak = false; // Kill Nihlathak before going to Throne Config.BaalHelper.FastChaos = false; // Kill Diablo before going to Throne Config.BaalHelper.DollQuit = false; // End script if Dolls (Undead Soul Killers) are found. + Config.BaalHelper.KillBaal = true; // Kill Baal. If set to false, you must configure Config.QuitList or the bot will wait indefinitely. + Config.BaalHelper.SkipTP = false; // Don't wait for a TP, go to WSK3 and wait for someone to go to throne. Anti PK measure. Scripts.Follower = false; // Script that follows a manually played leader around like a merc. For a list of commands, see Follower.js - Config.Follower.Leader = ""; // Leader's ingame name. This only applies to Follower script - - Config.QuitList = []; // List of character names to quit with. Example: Config.QuitList = ["MySorc", "MyDin"]; // *** special scripts *** - Scripts.Rusher = false; // Rush bot alpha version (no questing yet, only rushing), for a list of commands, see Rusher.js + Scripts.WPGetter = false; // Get missing waypoints + Scripts.GetKeys = false; // Hunt for T/H/D keys + Scripts.OrgTorch = false; + Config.OrgTorch.MakeTorch = true; // Convert organ sets to torches + Config.OrgTorch.WaitForKeys = true; // Enable Torch System to get keys from other profiles. See libs/TorchSystem.js for more info + 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. 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). + 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.Trigger = ".chant"; + Config.Enchant.Triggers = ["chant", "cows", "wps"]; // Chat commands for enchant, cow level and waypoint giving + Config.Enchant.GetLeg = false; // Get Wirt's Leg from Tristram. If set to false, it will check for the leg in town. + Config.Enchant.AutoChant = false; // Automatically enchant nearby players and their minions Config.Enchant.GameLength = 20; // Game length in minutes 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, alpha version - Config.ShopBot.ShopNPC = "Anya"; // Only Anya for now - // 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.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 = [Areas.Act1.Cave_Level_2, Areas.Act1.Underground_Passage_Level_2, Areas.Act1.Hole_Level_2, Areas.Act1.Pit_Level_2, Areas.Act1.Crypt, Areas.Act1.Mausoleum]; // List of act 1 areas to open chests in + Config.ChestMania.Act2 = [Areas.Act2.Stony_Tomb_Level_1, Areas.Act2.Stony_Tomb_Level_2, Areas.Act2.Ancient_Tunnels, Areas.Act2.Tal_Rashas_Tomb_1, Areas.Act2.Tal_Rashas_Tomb_2, Areas.Act2.Tal_Rashas_Tomb_3, Areas.Act2.Tal_Rashas_Tomb_4, Areas.Act2.Tal_Rashas_Tomb_5, Areas.Act2.Tal_Rashas_Tomb_6, Areas.Act2.Tal_Rashas_Tomb_7]; // List of act 2 areas to open chests in + Config.ChestMania.Act3 = [Areas.Act3.Lower_Kurast, Areas.Act3.Kurast_Bazaar, Areas.Act3.Upper_Kurast, Areas.Act3.A3_Sewers_Level_1, Areas.Act3.A3_Sewers_Level_2, Areas.Act3.Spider_Cave, Areas.Act3.Spider_Cavern, Areas.Act3.Swampy_Pit_Level_3]; // List of act 3 areas to open chests in + Config.ChestMania.Act4 = []; // List of act 4 areas to open chests in + Config.ChestMania.Act5 = [Areas.Act5.Glacial_Trail, Areas.Act5.Drifter_Cavern, Areas.Act5.Icy_Cellar, Areas.Act5.Abaddon, Areas.Act5.Pit_Of_Acheron, Areas.Act5.Infernal_Pit]; // List of act 5 areas to open chests in + 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 (Enums Example: [Areas.Act1.Cave_Level_2, Areas.Act3.Kurast_Bazaar, Areas.Act5.Pit_Of_Acheron]; Ref. at https://pastebin.com/pRFkqDzb) + + + // *** Guest scripts *** + + // Baal Assistant by YourGreatestMember + Scripts.BaalAssistant = false; // Used to leech or help in baal runs. + Config.BaalAssistant.Wait = 120; // Seconds to wait for a runner to be in the throne / portal wait / safe TP wait / hot TP wait... + Config.BaalAssistant.KillNihlathak = false; // Kill Nihlathak before going to Throne + Config.BaalAssistant.FastChaos = false; // Kill Diablo before going to Throne + Config.BaalAssistant.Helper = true; // Set to true to help attack, set false to to leech. + Config.BaalAssistant.GetShrine = false; // Set to true to get a experience shrine at the start of the run. + Config.BaalAssistant.GetShrineWaitForHotTP = false; // Set to true to get a experience shrine after leader shouts the hot tp message as defined in Config.BaalAssistant.HotTPMessage + Config.BaalAssistant.SkipTP = false; // Set to true to enable the helper to skip the TP and teleport down to the throne room. + Config.BaalAssistant.WaitForSafeTP = false; // Set to true to wait for a safe TP message (defined in SafeTPMessage) + Config.BaalAssistant.DollQuit = false; // Quit on dolls. (Hardcore players?) + Config.BaalAssistant.SoulQuit = false; // Quit on Souls. (Hardcore players?) + Config.BaalAssistant.KillBaal = true; // Set to true to kill baal, if you set to false you MUST configure Config.QuitList or Config.BaalAssistant.NextGameMessage or the bot will wait indefinitely. + Config.BaalAssistant.HotTPMessage = ["Hot"]; // Configure safe TP messages. + Config.BaalAssistant.SafeTPMessage = ["Safe", "Clear"]; // Configure safe TP messages. + Config.BaalAssistant.BaalMessage = ["Baal"]; // Configure baal messages, this is a precautionary measure. + Config.BaalAssistant.NextGameMessage = ["Next Game", "Next", "New Game"]; // Next Game message, this is a precautionary quit command, Reccomended setting up: Config.QuitList // Town settings Config.HealHP = 50; // Go to a healer if under designated percent of life. Config.HealMP = 0; // Go to a healer if under designated percent of mana. + Config.HealStatus = false; // Go to a healer if poisoned or cursed Config.UseMerc = true; // Use merc. This is ignored and always false in d2classic. Config.MercWatch = false; // Instant merc revive during battle. @@ -152,6 +237,8 @@ function LoadConfig() { Config.UseRejuvMP = 0; // Drink a rejuvenation potion if mana is under designated percent. Config.UseMercHP = 75; // Give a healing potion to your merc if his/her life is under designated percent. Config.UseMercRejuv = 0; // Give a rejuvenation potion to your merc if his/her life is under designated percent. + Config.HPBuffer = 0; // Number of healing potions to keep in inventory. + Config.MPBuffer = 0; // Number of mana potions to keep in inventory. Config.RejuvBuffer = 0; // Number of rejuvenation potions to keep in inventory. // Chicken settings @@ -191,87 +278,156 @@ function LoadConfig() { Config.MinColumn[2] = 0; Config.MinColumn[3] = 0; - // Pickit config - Config.PickitFiles.push("kolton.nip"); // Pickit filenames in /pickit/ folder + // Pickit config. Default folder is kolbot/pickit. + Config.PickitFiles.push("kolton.nip"); Config.PickitFiles.push("LLD.nip"); Config.PickRange = 40; // Pick radius Config.FastPick = false; // Check and pick items between attacks + // 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. 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. + Config.RepairPercent = 40; // Durability percent of any equipped item that will trigger repairs. // Gambling config Config.Gamble = false; 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 - - // Cubing config. All recipes are available in Templates/Cubing.txt + + // 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. 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. - // All ingredients will be auto-picked, for classids check libs/NTItemAlias.dbl - 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 + // Ingredients for the following recipes will be auto-picked, for classids check libs/NTItemAlias.dbl + + //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]); // 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, "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, "Diadem"]); // Reroll magic Diadem + //Config.Recipes.push([Recipe.Reroll.Magic, "Grand Charm"]); // Reroll magic Grand Charm (ilvl 91+) - 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.Glove, 452]); // Craft Hit Power Vambraces + //Config.Recipes.push([Recipe.Reroll.Rare, "Diadem"]); // Reroll rare Diadem - Config.Recipes.push([Recipe.Reroll.Magic, 421]); // Reroll magic Diadem - Config.Recipes.push([Recipe.Reroll.Rare, 421]); // 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, "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 - // Base item must be in the pickit, rest is auto-picked - Config.Recipes.push([Recipe.Socket.Weapon, 255]); // Socket Thresher - Config.Recipes.push([Recipe.Socket.Weapon, 256]); // Socket Cryptic Axe - Config.Recipes.push([Recipe.Socket.Armor, 442]); // Socket Sacred Armor - Config.Recipes.push([Recipe.Socket.Armor, 443]); // Socket Archon Plate + //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 - * !!!NOTE!!! enhanced damage and enhanced defense on runewords are broken in the core right now * 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.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"); + //Config.KeepRunewords.push("[type] == shield || [type] == auricshields # [fcr] == 35"); - // General config - Config.PublicMode = 0; // 1 = invite, 2 = accept, 0 = disable - Config.LastMessage = ""; // Message to say at the end of the run. + // Public game options + + // If Config.Leader is set, the bot will only accept invites from leader. If Config.PublicMode is not 0, Baal and Diablo script will open Town Portals. + Config.PublicMode = 0; // 1 = invite and accept, 2 = accept only, 3 = invite only, 0 = disable + // Party message settings. Each setting represents an array of messages that will be randomly chosen. + // $name, $level, $class and $killer are replaced by the player's name, level, class and killer + Config.Greetings = []; // Example: ["Hello, $name (level $level $class)"] + 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.MinGameTime = 60; // Min game time in seconds. Bot will stay in game if the run is completed before. + 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. 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. + + // Shrine Scanner - scan for shrines while moving. + // Put the shrine types in order of priority (from highest to lowest). For a list of types, see sdk/shrines.txt + Config.ScanShrines = []; // Available Shrines: [Shrines.refilling, Shrines.health, Shrines.mana, Shrines.experience, Shrines.skill, Shrines.resist_lightning, Shrines.resist_fire, Shrines.armor, Shrines.combat, Shrines.resist_cold, Shrines.resist_poison, Shrines.mana_recharge, Shrines.stamina, Shrines.portal, Shrines.gem, Shrines.monster, Shrines.exploding, Shrines.poison]; + + // MF Switch + Config.MFSwitchPercent = 0; // Boss life % to switch weapons at. Set to 0 to disable. + Config.MFSwitch = 0; // MF weapon slot: 0 = slot I, 1 = slot II + + // Fastmod config + Config.FCR = 0; // 0 - disable, 1 to 255 - set value of faster cast rate + Config.FHR = 0; // 0 - disable, 1 to 255 - set value of faster hit recovery + 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 Config.HostileAction = 0; // 0 - quit immediately, 1 - quit when hostile player is sighted, 2 - attack hostile + Config.TownOnHostile = false; // Go to town instead of quitting when HostileAction is 0 or 1 + Config.RandomPrecast = false; // Anti-PK measure, only supported in Baal and BaalHelper and BaalAssisstant at the moment. + Config.ViperCheck = false; // Quit if revived Tomb Vipers are sighted // DClone config 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". @@ -286,19 +442,45 @@ function LoadConfig() { /* Attack config * To disable an attack, set it to -1 * Skills MUST be POSITIVE numbers. For reference see http://pastebin.com/baShRwWM + * Example of Enums using: Config.AttackSkill[1] = Skills.Paladin.Blessed_Hammer; For Reference see https://pastebin.com/K7qCZw81 */ Config.AttackSkill[0] = -1; // Preattack skill. - Config.AttackSkill[1] = -1; // Primary skill to bosses. - Config.AttackSkill[2] = -1; // Primary skill to others. - Config.AttackSkill[3] = -1; // Secondary skill if monster is immune to primary. - Config.AttackSkill[4] = -1; // Backup skill, used when out of mana or when whirlwind path is blocked + Config.AttackSkill[1] = -1; // Primary skill for bosses. + Config.AttackSkill[2] = -1; // Backup/Immune skill for bosses. + Config.AttackSkill[3] = -1; // Primary skill for others. + Config.AttackSkill[4] = -1; // Backup/Immune skill for others. + + // 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 + // Wereform setup. Make sure you read Templates/Attacks.txt for attack skill format. + Config.Wereform = false; // 0 / false - don't shapeshift, 1 / "Werewolf" - change to werewolf, 2 / "Werebear" - change to werebear + // Class specific config Config.BOSwitch = 0; // Precast weapon slot - 0 = slot I, 1 = slot II Config.FindItem = false; // Use Find Item skill on corpses after clearing. Config.FindItemSwitch = 0; // Find Item weapon slot - 0 = slot I, 1 = slot II - Config.Werewolf = false; // EXPERIMENTAL werewolf attack for Wolfhowl Barbarians. Set attacks to feral rage. + + + // AutoBuild System ( See /d2bs/kolbot/libs/config/Builds/README.txt for instructions ) + Config.AutoBuild.Enabled = false; // This will enable or disable the AutoBuild system + + Config.AutoBuild.Template = "BuildName"; // The name of the build associated with an existing + // template filename located in libs/config/Builds/ + + Config.AutoBuild.Verbose = true; // Allows script to print messages in console + Config.AutoBuild.DebugMode = true; // Debug mode prints a little more information to console and + // logs activity to /logs/AutoBuild.CharacterName._MM_DD_YYYY.log + // It automatically enables Config.AutoBuild.Verbose } \ No newline at end of file diff --git a/d2bs/kolbot/libs/config/Builds/Class.Build.js b/d2bs/kolbot/libs/config/Builds/Class.Build.js new file mode 100644 index 000000000..3bffd974b --- /dev/null +++ b/d2bs/kolbot/libs/config/Builds/Class.Build.js @@ -0,0 +1,915 @@ +// /d2bs/kolbot/libs/config/Builds/Class.Build.js + +/** +* +* Instructions: See /d2bs/kolbot/libs/config/Builds/README.txt +* +* Skill IDs: See /d2bs/kolbot/sdk/skills.txt for a list of skill IDs. +* +* Stat IDs: +* +* Strength = 0 +* Energy = 1 +* Dexterity = 2 +* Vitality = 3 +* +*/ +js_strict(true); + +if (!isIncluded("common/Cubing.js")) { include("common/Cubing.js"); }; +if (!isIncluded("common/Prototypes.js")) { include("common/Prototypes.js"); }; +if (!isIncluded("common/Runewords.js")) { include("common/Runewords.js"); }; + +var AutoBuildTemplate = { + + 1: { + //SkillPoints: [-1], // This doesn't matter. We don't have skill points to spend at lvl 1 + //StatPoints: [-1,-1,-1,-1,-1], // This doesn't matter. We don't have stat points to spend at lvl 1 + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 2: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 3: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 4: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 5: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 6: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 7: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 8: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 9: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 10: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 11: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 12: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 13: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 14: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 15: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 16: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 17: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 18: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 19: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 20: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 21: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 22: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 23: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 24: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 25: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 26: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 27: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 28: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 29: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 30: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 31: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 32: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 33: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 34: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 35: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 36: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 37: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 38: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 39: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 40: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 41: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 42: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 43: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 44: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 45: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 46: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 47: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 48: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 49: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 50: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 51: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 52: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 53: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 54: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 55: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 56: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 57: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 58: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 59: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 60: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 61: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 62: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 63: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 64: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 65: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 66: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 67: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 68: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 69: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 70: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 71: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 72: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 73: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 74: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 75: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 76: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 77: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 78: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 79: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 80: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 81: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 82: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 83: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 84: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 85: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 86: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 87: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 88: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 89: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 90: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 91: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 92: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 93: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 94: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 95: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 96: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 97: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 98: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 99: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + } +}; diff --git a/d2bs/kolbot/libs/config/Builds/README.txt b/d2bs/kolbot/libs/config/Builds/README.txt new file mode 100644 index 000000000..f0237c378 --- /dev/null +++ b/d2bs/kolbot/libs/config/Builds/README.txt @@ -0,0 +1,225 @@ +README.txt - AutoBuild Script Installation and Configuration + + + DISCLAIMER: By continuing to read this file and use these scripts you agree that I + take no responsibility for anything that may happen to yourself, your character, or your account + as a result of the use or misuse of these files. + + + This file will help guide you through installing and configuring the AutoBuild scripts + in kolbot Temp branch (SHA-1: c82de3efbdcd62b82ffda3a8d93eecd512cd956a) + + Also, I'm going to make and post a patch for anyone that wishes to use that instead. + If you apply the patch, you can start reading at step 5. + + + + +1. Extract the contents of the AutoBuild.zip file to base directory located at + /d2bs/kolbot/ (Do not add the filename to the extraction path) + + NOTE: Nothing should be overwritten in this step.. You can/should actually + disable automatic overwrite of files in your zip extracting software. + + + + +2. Verify that the following files exist in these locations: + /d2bs/kolbot/tools/AutoBuildThread.js + /d2bs/kolbot/libs/common/AutoBuild.js + /d2bs/kolbot/libs/config/Builds/Class.Build.js + /d2bs/kolbot/libs/config/Builds/README.txt + /d2bs/kolbot/libs/config/Builds/Sorceress.ExampleBuild.js + + + + +3. Add this "AutoBuild" sub-object enclosed in the lines of forward slashes to the end of your + Config object in file /d2bs/kolbot/libs/common/Config.js. The ClearAnyArea, Rusher, and Rushee sub-objects + have nothing to do with the AutoBuild scripts, they were included for context. + + ClearAnyArea: { + AreaList: [] + }, + Rusher: { + WaitPlayerCount: 0 + }, + Rushee: { + Quester: false, + Bumper: false + }, // <------- NOTE THE ADDED COMMA! + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + AutoBuild: { + Enabled: false, + Template: "", + Verbose: false, + DebugMode: false + } +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +}; + + + + +4. Add the try/catch block enclosed in the lines of forward slashes to the end of your Config object's "init" + function in file /d2bs/kolbot/libs/common/Config.js. The surrounding material is shown for context. + + try { + LoadConfig.call(); + } catch (e2) { + if (notify) { + 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")) { + AutoBuild.initialize(); + } + } catch (e3) { + print("ÿc8Error in libs/common/AutoBuild.js (AutoBuild system is not active!)"); + print(e3.toSource()); + } +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + }, + + // Time + StartDelay: 0, + PickDelay: 0, + AreaDelay: 0, + MinGameTime: 0, + MaxGameTime: 0, + + // Healing and chicken + LifeChicken: 0, + ManaChicken: 0, + UseHP: 0, + + + + +5. Next, create a copy of the base build template provided /d2bs/kolbot/libs/config/Builds/Class.Build.js + and rename it in the following format: "CharacterClass.BuildName.js" + + For example, if you want to make a template for a hammerdin, + you would name the file something like "Paladin.Hammerdin.js" or "Paladin.MyHdin.js" + + + + +6. Add this section to your char config file. + + Config.AutoBuild.Enabled = false; // This will enable or disable the AutoBuild system + + Config.AutoBuild.Template = "BuildName"; // The name of the build associated with an existing + // template filename located in libs/config/Builds/ + // See libs/config/Builds/README.txt for instructions + + Config.AutoBuild.Verbose = true; // Allows script to print messages in console + + Config.AutoBuild.DebugMode = true; // Debug mode prints a little more information to console and + // logs activity to /logs/AutoBuild.CharacterName._MM_DD_YYYY.log + // It automatically enables Config.AutoBuild.Verbose + + + + +7. Now you need to set your config variables. + + To enable or disable the AutoBuild system, adjust the boolean Config.AutoBuild.Enabled accordingly. + Set Config.AutoBuild.Template to a string value which represents the "BuildName" part of your + build template filename you created in step 5. + + For example, if your template filename is "Paladin.Hammerdin.js" you would write Config.AutoBuild.Template = "Hammerdin"; + in your char config file. If your template filename is "Paladin.MyHdin.js", you would write Config.AutoBuild.Template = "MyHdin"; + + If you want to see script messages in the D2BS console, set Config.AutoBuild.Verbose = true; + If you want to log script messages and display some extra information in certain cases in the console and log file, + set Config.AutoBuild.DebugMode = true; + + + + +8. Now that the easy part is done you will need to edit your build template that you created in step 5. + This is the point where it's worth explaining some of the internal behavior of these scripts. + Please read the whole section below before actually editing any of the file! + + The best way to think of this AutoBuild system is an automation system for your char config settings. + You still need to make and setup a basic char config file for your character or profile + just as you normally would to run without the AutoBuild system enabled. (See https://github.com/kolton/d2bot-with-kolbot/wiki) + This script just adjusts and overwrites anything you want it to within your Config object once it's loaded by kolbot. + (NOTE: Overwrites the char config in memory, not on disk!) + + When the threaded helper script detects that your character has gained a level, it looks up the skills and stats + you have set in your build template file (step 5), validates them, and spends them according to your template. + + Then the helper script broadcasts to the other scripts that your character has gained a level. + When this happens, all scripts that are using the AutoBuild system will update their local copy of the "Config" object which, + as you know, is where all of your character configuration settings live while your bot is running. This occurs through the "Update" + functions that are defined for each level of your build template. + + This system gives you the power to adjust your character configuration settings on-the-fly, without having to reload any + scripts or wait for the next game (for some things). Since all of the kolbot libraries use your char config settings to make decisions, + you can alter the overall behavior of the bot on a per-level basis without having to spend time making manual changes + to your character config file every time you want to bot a different area. + + For example, when you level up, you can set this to add a new skill point, and then immediately adjust the Config object + to use this newly acquired skill as your main attack. + + The build template is one large object named "AutoBuildTemplate". Don't change the name. + It's comprised of 99 sub-objects which are indexed by character level (Number). + At every character level (except level 1) you may set skill and stat points which the bot will spend when it reaches that level. + Lookup skill ids in the /d2bs/kolbot/sdk/ folder. Valid stat ids are 0 (Strength), 1 (Energy), 2 (Dexterity), or 3 (Vitality). + You may set multiple skill and stat points per level. Anything set to -1 will be silently ignored, so you can use -1 if + you don't want to spend points at a certain level. (Or just completely remove the value from the array) + + NOTE: The scripts DO NOT limit the number of skills and stats spent upon each level up event. + You are responsible for keeping track of the number of accrued points versus the number of points spent + at each level in your build template. However, there are safety measures in place to prevent spending points your character doesn't have. + I suggest not trying to spend points based on whether a quest was completed or not, unless you really know what you are doing and write + the additional logic required to make that determination. + + Every time you level up, the "Update" function within the corresponding character level is called. + This is where you make CHANGES to the "Config" object. You can make changes in the same format you usually do in your char config file. + + For example, at level four if you want to start running the Corpsefire/Den of Evil script, you would do something like this. + + + 4: { + SkillPoint: 37, // Warmth + 1 + StatPoints: [0, 0, 0, 3, 3], // Strength + 3 , Vitality + 2 + Update: function () { + Scripts.Corpsefire = true; // Try going for Corpsefire now that we're level 4 + Config.Corpsefire.ClearDen = true; + Config.BeltColumn = ["hp", "hp", "mp", "rv"]; // Replace mana pots with rejuvs since we have +1 Warmth + Config.MinColumn = [1, 1, 1, 0]; + } + }, + + + If you know javascript you may be interested to know that the "Update" function is called with its "this" identifier pointing to the "Config" object. + Therefore changing the values using "this" instead of "Config" (ie, this.BeltColumn = ... vs Config.BeltColumn = ...) might be marginally faster, + but I'm not sure it really matters so much. + + It's also worth noting that at the start of every game, each "Update" function in your build template is executed, in order, from level 1 to + your current character level. This is done in order to preserve the integrity of the Config object across multiple games without having + to save over the char config file on disk. + + So basically, any changes you want to undo from a previous level's Update function, you need to do programmatically or + comment it out in the previous level's Update function. Making changes programatically is MUCH better and will lead to less hastle, + especially if you are using the same build template for multiple characters! + + Please take a look at the "ExampleBuild" for Sorceresses at /d2bs/kolbot/libs/config/Builds/Sorceress.ExampleBuild.js + for more example code/setup/usage. + + Enjoy the ladder reset and good luck! + + + - alogwe + diff --git a/d2bs/kolbot/libs/config/Builds/Sorceress.ExampleBuild.js b/d2bs/kolbot/libs/config/Builds/Sorceress.ExampleBuild.js new file mode 100644 index 000000000..df081ea11 --- /dev/null +++ b/d2bs/kolbot/libs/config/Builds/Sorceress.ExampleBuild.js @@ -0,0 +1,938 @@ +// /d2bs/kolbot/libs/Builds/Sorceress.ExampleBuild.js + +/** +* +* Instructions: See /d2bs/kolbot/libs/config/Builds/README.txt +* +* Skill IDs: See /d2bs/kolbot/sdk/skills.txt for a list of skill IDs. +* +* Stat IDs: +* +* Strength = 0 +* Energy = 1 +* Dexterity = 2 +* Vitality = 3 +* +*/ +js_strict(true); + +if (!isIncluded("common/Cubing.js")) { include("common/Cubing.js"); }; +if (!isIncluded("common/Prototypes.js")) { include("common/Prototypes.js"); }; +if (!isIncluded("common/Runewords.js")) { include("common/Runewords.js"); }; + +var AutoBuildTemplate = { + + 1: { + //SkillPoints: [-1], // This doesn't matter. We don't have skill points to spend at lvl 1 + //StatPoints: [-1,-1,-1,-1,-1], // This doesn't matter. We don't have stat points to spend at lvl 1 + Update: function () { + + Scripts.ClearAnyArea = true; // We are only level 1 so we will start by clearing Blood Moor + Config.ClearAnyArea.AreaList = [Areas.Act1.Blood_Moor]; + Config.ClearType = 0; // Monster spectype to kill in level clear scripts (0 = all) + + // Config.PickitFiles.push("level/1.nip"); // File "level/1.nip" is not included, it's just an example. + + Config.OpenChests = true; // Open chests. Controls key buying. + Config.LogExperience = false; // Print experience statistics in the manager. + Config.StashGold = 200; // Minimum amount of gold to stash. + Config.AttackSkill = [Skills.common.Attack, Skills.Sorceress.Fire_Bolt, Skills.None, Skills.Sorceress.Fire_Bolt, Skills.Sorceress.Fire_Bolt, Skills.common.Attack, Skills.common.Attack]; // At level 1 we start with a +1 Fire Bolt staff + Config.LowManaSkill = [Skills.common.Attack, Skills.common.Attack]; + Config.PublicMode = 1; + Config.ScanShrines = [Shrines.experience, Shrines.mana_recharge, Shrines.skill, Shrines.stamina, Shrines.combat, Shrines.armor, Shrines.health]; + Config.BeltColumn = ["hp", "hp", "hp", "mp"]; // Keep tons of health potions! + } + }, + + 2: { + SkillPoints: [Skills.Sorceress.Fire_Bolt], // Fire Bolt + 1 + StatPoints: [Stats.strength, Stats.vitality, Stats.vitality, Stats.vitality, Stats.vitality], // Strength + 1 , Vitality + 4 + Update: function () { + // Config.PickitFiles.splice(Config.PickitFiles.indexOf("level/1.nip"), 1); // Will remove index "level/1.nip" from Config.PickitFiles + // Config.PickitFiles.push("level/2.nip"); + Config.BeltColumn = ["hp", "hp", "mp", "mp"]; + Config.MinColumn = [1, 1, 1, 1]; + } + }, + + 3: { + SkillPoints: [Skills.Sorceress.Ice_Bolt], // Ice Bolt + 1 + StatPoints: [Stats.strength, Stats.strength, Stats.vitality, Stats.vitality, Stats.vitality], // Strength + 2 , Vitality + 3 + Update: function () { + Config.AttackSkill = [Skills.Sorceress.Ice_Bolt, Skills.Sorceress.Fire_Bolt, Skills.None, Skills.Sorceress.Fire_Bolt, Skills.common.Attack, Skills.common.Attack, Skills.common.Attack]; // Ice Bolt and Fire Bolt + } + }, + + 4: { + SkillPoints: [Skills.Sorceress.Warmth], // Warmth + 1 + StatPoints: [Stats.strength, Stats.strength, Stats.strength, Stats.vitality, Stats.vitality], // Strength + 3 , Vitality + 2 + Update: function () { + Scripts.Corpsefire = true; // Lets try Corpsefire now that we're level 4 + Config.Corpsefire.ClearDen = true; + + Scripts.ClearAnyArea = false; // Don't want to clear Blood Moor anymore (See lvl 1 above) + Config.ClearAnyArea.AreaList = []; + + Config.BeltColumn = ["hp", "hp", "mp", "rv"]; // Start keeping rejuvs since we have +1 Warmth + Config.MinColumn = [1, 1, 1, 0]; + } + }, + + 5: { + SkillPoints: [Skills.Sorceress.Charged_Bolt], // Charged Bolt + 1 + StatPoints: [Stats.strength, Stats.strength, Stats.strength, Stats.strength, Stats.vitality], // Strength + 4 , Vitality + 1 + Update: function () { + + Scripts.ClearAnyArea = true; // Now we'll try enabling it again Cold Plains and Stony Field + Config.ClearAnyArea.AreaList = [Areas.Act1.Cold_Plains, Areas.Act1.Stony_Field]; + + Config.ScanShrines = [Shrines.experience, Shrines.mana_recharge, Shrines.skill]; + Config.AttackSkill = Skills.common.Attack, Skills.Sorceress.Fire_Bolt, Skills.None, Skills.Sorceress.Charged_Bolt, Skills.common.Attack, Skills.Sorceress.Ice_Bolt, Skills.common.Attack]; // All the bolts! + } + }, + + 6: { + SkillPoints: [Skills.Sorceress.Fire_Bolt], // Fire Bolt + 1 + StatPoints: [Stats.strength, Stats.strength, Stats.vitality, Stats.vitality, Stats.dexterity], // Strength + 2 , Vitality + 2, Dexterity + 1 + Update: function () { + Config.AttackSkill = [Skills.Sorceress.Ice_Bolt, Skills.Sorceress.Fire_Bolt, Skills.None, Skills.Sorceress.Fire_Bolt, Skills.common.Attack, Skills.Sorceress.Charged_Bolt, Skills.common.Attack]; // All the bolts! + } + }, + + 7: { + SkillPoints: [-1], // TODO + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 8: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 9: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 10: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 11: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 12: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 13: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 14: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 15: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 16: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 17: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 18: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 19: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 20: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 21: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 22: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 23: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 24: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 25: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 26: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 27: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 28: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 29: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 30: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 31: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 32: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 33: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 34: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 35: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 36: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 37: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 38: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 39: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 40: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 41: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 42: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 43: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 44: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 45: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 46: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 47: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 48: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 49: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 50: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 51: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 52: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 53: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 54: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 55: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 56: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 57: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 58: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 59: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 60: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 61: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 62: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 63: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 64: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 65: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 66: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 67: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 68: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 69: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 70: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 71: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 72: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 73: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 74: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 75: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 76: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 77: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 78: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 79: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 80: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 81: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 82: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 83: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 84: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 85: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 86: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 87: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 88: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 89: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 90: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 91: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 92: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 93: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 94: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 95: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 96: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 97: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 98: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + }, + + 99: { + SkillPoints: [-1], + StatPoints: [-1,-1,-1,-1,-1], + Update: function () { + Config.AttackSkill = [-1,-1,-1,-1,-1,-1,-1]; + Config.LowManaSkill = [-1,-1]; + } + } +}; diff --git a/d2bs/kolbot/libs/config/Druid.js b/d2bs/kolbot/libs/config/Druid.js index b8f5e82ae..47ff36066 100644 --- a/d2bs/kolbot/libs/config/Druid.js +++ b/d2bs/kolbot/libs/config/Druid.js @@ -20,6 +20,7 @@ function LoadConfig() { Scripts.BattleOrders = false; Config.BattleOrders.Mode = 0; // 0 = give BO, 1 = get BO Config.BattleOrders.Wait = false; // Idle until the player that received BO leaves. + Config.BattleOrders.Getters = []; // List of players to wait for before casting Battle Orders (mode 0). All players must be in the same area as the BOer. // Team MF system Config.MFLeader = false; // Set to true if you have one or more MFHelpers. Opens TP and gives commands when doing normal MF runs. @@ -34,8 +35,10 @@ function LoadConfig() { Config.Mausoleum.ClearCrypt = false; Scripts.Rakanishu = false; Config.Rakanishu.KillGriswold = true; + Scripts.UndergroundPassage = false; Scripts.Coldcrow = false; Scripts.Tristram = false; + Config.Tristram.PortalLeech = false; // Set to true to open a portal for leechers. Scripts.Pit = false; Config.Pit.ClearPit1 = true; Scripts.Treehead = false; @@ -48,26 +51,31 @@ function LoadConfig() { // *** act 2 *** Scripts.Radament = false; + Scripts.Coldworm = false; + Config.Coldworm.KillBeetleburst = false; + Config.Coldworm.ClearMaggotLair = false; // Clear all 3 levels Scripts.AncientTunnels = false; + Config.AncientTunnels.OpenChest = false; // Open special chest in Lost City + Config.AncientTunnels.KillDarkElder = false; Scripts.Summoner = false; + Config.Summoner.FireEye = false; Scripts.Tombs = false; Scripts.Duriel = false; // *** act 3 *** Scripts.Stormtree = false; - Scripts.KurastChests = false; - Config.KurastChests.LowerKurast = true; - Config.KurastChests.Bazaar = false; - Config.KurastChests.Sewers1 = false; - Config.KurastChests.Sewers2 = false; Scripts.KurastTemples = false; Scripts.Icehawk = false; Scripts.Endugu = false; Scripts.Travincal = false; + Config.Travincal.PortalLeech = false; // Set to true to open a portal for leechers. Scripts.Mephisto = false; Config.Mephisto.MoatTrick = false; + Config.Mephisto.KillCouncil = false; + Config.Mephisto.TakeRedPortal = true; // *** act 4 *** + Scripts.OuterSteppes = false; Scripts.Izual = false; Scripts.Hephasto = false; Scripts.Vizier = false; // Intended for classic sorc, kills Vizier only. @@ -77,9 +85,12 @@ function LoadConfig() { Config.Diablo.SealWarning = "Leave the seals alone!"; 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; + Config.Pindleskin.UseWaypoint = false; Config.Pindleskin.KillNihlathak = true; Config.Pindleskin.ViperQuit = false; // End script if Tomb Vipers are found. Scripts.Nihlathak = false; @@ -89,59 +100,133 @@ function LoadConfig() { Config.Eldritch.KillShenk = true; Config.Eldritch.KillDacFarren = true; Scripts.Eyeback = false; + Scripts.SharpTooth = false; Scripts.ThreshSocket = false; Scripts.Abaddon = false; Scripts.Frozenstein = false; Config.Frozenstein.ClearFrozenRiver = true; Scripts.Bonesaw = false; + Config.Bonesaw.ClearDrifterCavern = false; Scripts.Snapchip = false; Config.Snapchip.ClearIcyCellar = true; + Scripts.Worldstone = false; Scripts.Baal = false; - Config.Baal.HotTPMsg = "Hot TP!"; - Config.Baal.SafeTPMsg = "TP safe!"; - Config.Baal.BaalMsg = "Baal"; - Config.Baal.DollQuit = false; // End script if Dolls (Undead Soul Killers) are found. + Config.Baal.HotTPMessage = "Hot TP!"; + Config.Baal.SafeTPMessage = "Safe TP!"; + Config.Baal.BaalMessage = "Baal!"; + Config.Baal.SoulQuit = false; // End script if Souls (Undead Soul Killers) are found. + Config.Baal.DollQuit = false; // End script if Dolls (Undead Stigyan Dolls) are found. + Config.Baal.KillBaal = true; // Kill Baal. Leaves game after wave 5 if false. /* ### leeching section ### * Unless stated otherwise, leader's character name isn't needed on order to run. * Don't use more scripts of the same type! (Run AutoBaal OR BaalHelper, not both) */ + 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.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; // Find shrine when hot tp message is sent. You can change messages in AutoBaal.js + 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 + Config.AutoBaal.LongRangeSupport = false; // Cast long distance skills from a safe spot Scripts.BaalHelper = false; + Config.BaalHelper.Wait = 120; // Seconds to wait for a runner to be in Throne Config.BaalHelper.KillNihlathak = false; // Kill Nihlathak before going to Throne Config.BaalHelper.FastChaos = false; // Kill Diablo before going to Throne Config.BaalHelper.DollQuit = false; // End script if Dolls (Undead Soul Killers) are found. + Config.BaalHelper.KillBaal = true; // Kill Baal. If set to false, you must configure Config.QuitList or the bot will wait indefinitely. + Config.BaalHelper.SkipTP = false; // Don't wait for a TP, go to WSK3 and wait for someone to go to throne. Anti PK measure. Scripts.Follower = false; // Script that follows a manually played leader around like a merc. For a list of commands, see Follower.js - Config.Follower.Leader = ""; // Leader's ingame name. This only applies to Follower script - - Config.QuitList = []; // List of character names to quit with. Example: Config.QuitList = ["MySorc", "MyDin"]; // *** special scripts *** - Scripts.Rusher = false; // Rush bot alpha version (no questing yet, only rushing), for a list of commands, see Rusher.js + Scripts.WPGetter = false; // Get missing waypoints + Scripts.GetKeys = false; // Hunt for T/H/D keys + Scripts.OrgTorch = false; + Config.OrgTorch.MakeTorch = true; // Convert organ sets to torches + Config.OrgTorch.WaitForKeys = true; // Enable Torch System to get keys from other profiles. See libs/TorchSystem.js for more info + 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. 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). + 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.Trigger = ".chant"; + Config.Enchant.Triggers = ["chant", "cows", "wps"]; // Chat commands for enchant, cow level and waypoint giving + Config.Enchant.GetLeg = false; // Get Wirt's Leg from Tristram. If set to false, it will check for the leg in town. + Config.Enchant.AutoChant = false; // Automatically enchant nearby players and their minions Config.Enchant.GameLength = 20; // Game length in minutes 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, alpha version - Config.ShopBot.ShopNPC = "Anya"; // Only Anya for now - // 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.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 = [Areas.Act1.Cave_Level_2, Areas.Act1.Underground_Passage_Level_2, Areas.Act1.Hole_Level_2, Areas.Act1.Pit_Level_2, Areas.Act1.Crypt, Areas.Act1.Mausoleum]; // List of act 1 areas to open chests in + Config.ChestMania.Act2 = [Areas.Act2.Stony_Tomb_Level_1, Areas.Act2.Stony_Tomb_Level_2, Areas.Act2.Ancient_Tunnels, Areas.Act2.Tal_Rashas_Tomb_1, Areas.Act2.Tal_Rashas_Tomb_2, Areas.Act2.Tal_Rashas_Tomb_3, Areas.Act2.Tal_Rashas_Tomb_4, Areas.Act2.Tal_Rashas_Tomb_5, Areas.Act2.Tal_Rashas_Tomb_6, Areas.Act2.Tal_Rashas_Tomb_7]; // List of act 2 areas to open chests in + Config.ChestMania.Act3 = [Areas.Act3.Lower_Kurast, Areas.Act3.Kurast_Bazaar, Areas.Act3.Upper_Kurast, Areas.Act3.A3_Sewers_Level_1, Areas.Act3.A3_Sewers_Level_2, Areas.Act3.Spider_Cave, Areas.Act3.Spider_Cavern, Areas.Act3.Swampy_Pit_Level_3]; // List of act 3 areas to open chests in + Config.ChestMania.Act4 = []; // List of act 4 areas to open chests in + Config.ChestMania.Act5 = [Areas.Act5.Glacial_Trail, Areas.Act5.Drifter_Cavern, Areas.Act5.Icy_Cellar, Areas.Act5.Abaddon, Areas.Act5.Pit_Of_Acheron, Areas.Act5.Infernal_Pit]; // List of act 5 areas to open chests in + 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 (Enums Example: [Areas.Act1.Cave_Level_2, Areas.Act3.Kurast_Bazaar, Areas.Act5.Pit_Of_Acheron]; Ref. at https://pastebin.com/pRFkqDzb) + + + // *** Guest scripts *** + + // Baal Assistant by YourGreatestMember + Scripts.BaalAssistant = false; // Used to leech or help in baal runs. + Config.BaalAssistant.Wait = 120; // Seconds to wait for a runner to be in the throne / portal wait / safe TP wait / hot TP wait... + Config.BaalAssistant.KillNihlathak = false; // Kill Nihlathak before going to Throne + Config.BaalAssistant.FastChaos = false; // Kill Diablo before going to Throne + Config.BaalAssistant.Helper = true; // Set to true to help attack, set false to to leech. + Config.BaalAssistant.GetShrine = false; // Set to true to get a experience shrine at the start of the run. + Config.BaalAssistant.GetShrineWaitForHotTP = false; // Set to true to get a experience shrine after leader shouts the hot tp message as defined in Config.BaalAssistant.HotTPMessage + Config.BaalAssistant.SkipTP = false; // Set to true to enable the helper to skip the TP and teleport down to the throne room. + Config.BaalAssistant.WaitForSafeTP = false; // Set to true to wait for a safe TP message (defined in SafeTPMessage) + Config.BaalAssistant.DollQuit = false; // Quit on dolls. (Hardcore players?) + Config.BaalAssistant.SoulQuit = false; // Quit on Souls. (Hardcore players?) + Config.BaalAssistant.KillBaal = true; // Set to true to kill baal, if you set to false you MUST configure Config.QuitList or Config.BaalAssistant.NextGameMessage or the bot will wait indefinitely. + Config.BaalAssistant.HotTPMessage = ["Hot"]; // Configure safe TP messages. + Config.BaalAssistant.SafeTPMessage = ["Safe", "Clear"]; // Configure safe TP messages. + Config.BaalAssistant.BaalMessage = ["Baal"]; // Configure baal messages, this is a precautionary measure. + Config.BaalAssistant.NextGameMessage = ["Next Game", "Next", "New Game"]; // Next Game message, this is a precautionary quit command, Reccomended setting up: Config.QuitList // Town settings Config.HealHP = 50; // Go to a healer if under designated percent of life. Config.HealMP = 0; // Go to a healer if under designated percent of mana. + Config.HealStatus = false; // Go to a healer if poisoned or cursed Config.UseMerc = true; // Use merc. This is ignored and always false in d2classic. Config.MercWatch = false; // Instant merc revive during battle. @@ -152,6 +237,8 @@ function LoadConfig() { Config.UseRejuvMP = 0; // Drink a rejuvenation potion if mana is under designated percent. Config.UseMercHP = 75; // Give a healing potion to your merc if his/her life is under designated percent. Config.UseMercRejuv = 0; // Give a rejuvenation potion to your merc if his/her life is under designated percent. + Config.HPBuffer = 0; // Number of healing potions to keep in inventory. + Config.MPBuffer = 0; // Number of mana potions to keep in inventory. Config.RejuvBuffer = 0; // Number of rejuvenation potions to keep in inventory. // Chicken settings @@ -191,87 +278,156 @@ function LoadConfig() { Config.MinColumn[2] = 0; Config.MinColumn[3] = 0; - // Pickit config - Config.PickitFiles.push("kolton.nip"); // Pickit filenames in /pickit/ folder + // Pickit config. Default folder is kolbot/pickit. + Config.PickitFiles.push("kolton.nip"); Config.PickitFiles.push("LLD.nip"); Config.PickRange = 40; // Pick radius Config.FastPick = false; // Check and pick items between attacks + // 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. 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. + Config.RepairPercent = 40; // Durability percent of any equipped item that will trigger repairs. // Gambling config Config.Gamble = false; 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 - - // Cubing config. All recipes are available in Templates/Cubing.txt + + // 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. 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. - // All ingredients will be auto-picked, for classids check libs/NTItemAlias.dbl - 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 + // Ingredients for the following recipes will be auto-picked, for classids check libs/NTItemAlias.dbl + + //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]); // 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, "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, "Diadem"]); // Reroll magic Diadem + //Config.Recipes.push([Recipe.Reroll.Magic, "Grand Charm"]); // Reroll magic Grand Charm (ilvl 91+) - 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.Glove, 452]); // Craft Hit Power Vambraces + //Config.Recipes.push([Recipe.Reroll.Rare, "Diadem"]); // Reroll rare Diadem - Config.Recipes.push([Recipe.Reroll.Magic, 421]); // Reroll magic Diadem - Config.Recipes.push([Recipe.Reroll.Rare, 421]); // 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, "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 - // Base item must be in the pickit, rest is auto-picked - Config.Recipes.push([Recipe.Socket.Weapon, 255]); // Socket Thresher - Config.Recipes.push([Recipe.Socket.Weapon, 256]); // Socket Cryptic Axe - Config.Recipes.push([Recipe.Socket.Armor, 442]); // Socket Sacred Armor - Config.Recipes.push([Recipe.Socket.Armor, 443]); // Socket Archon Plate + //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 - * !!!NOTE!!! enhanced damage and enhanced defense on runewords are broken in the core right now * 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.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"); + //Config.KeepRunewords.push("[type] == shield || [type] == auricshields # [fcr] == 35"); - // General config - Config.PublicMode = 0; // 1 = invite, 2 = accept, 0 = disable - Config.LastMessage = ""; // Message to say at the end of the run. + // Public game options + + // If Config.Leader is set, the bot will only accept invites from leader. If Config.PublicMode is not 0, Baal and Diablo script will open Town Portals. + Config.PublicMode = 0; // 1 = invite and accept, 2 = accept only, 3 = invite only, 0 = disable + // Party message settings. Each setting represents an array of messages that will be randomly chosen. + // $name, $level, $class and $killer are replaced by the player's name, level, class and killer + Config.Greetings = []; // Example: ["Hello, $name (level $level $class)"] + 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.MinGameTime = 60; // Min game time in seconds. Bot will stay in game if the run is completed before. + 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. 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. + + // Shrine Scanner - scan for shrines while moving. + // Put the shrine types in order of priority (from highest to lowest). For a list of types, see sdk/shrines.txt + Config.ScanShrines = []; // Available Shrines: [Shrines.refilling, Shrines.health, Shrines.mana, Shrines.experience, Shrines.skill, Shrines.resist_lightning, Shrines.resist_fire, Shrines.armor, Shrines.combat, Shrines.resist_cold, Shrines.resist_poison, Shrines.mana_recharge, Shrines.stamina, Shrines.portal, Shrines.gem, Shrines.monster, Shrines.exploding, Shrines.poison]; + + // MF Switch + Config.MFSwitchPercent = 0; // Boss life % to switch weapons at. Set to 0 to disable. + Config.MFSwitch = 0; // MF weapon slot: 0 = slot I, 1 = slot II + + // Fastmod config + Config.FCR = 0; // 0 - disable, 1 to 255 - set value of faster cast rate + Config.FHR = 0; // 0 - disable, 1 to 255 - set value of faster hit recovery + 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 Config.HostileAction = 0; // 0 - quit immediately, 1 - quit when hostile player is sighted, 2 - attack hostile + Config.TownOnHostile = false; // Go to town instead of quitting when HostileAction is 0 or 1 + Config.RandomPrecast = false; // Anti-PK measure, only supported in Baal and BaalHelper and BaalAssisstant at the moment. + Config.ViperCheck = false; // Quit if revived Tomb Vipers are sighted // DClone config 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". @@ -286,6 +442,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 + * Example of Enums using: Config.AttackSkill[1] = Skills.Paladin.Blessed_Hammer; For Reference see https://pastebin.com/K7qCZw81 */ Config.AttackSkill[0] = -1; // Preattack skill. Config.AttackSkill[1] = -1; // Primary skill to bosses. @@ -295,13 +452,40 @@ function LoadConfig() { Config.AttackSkill[5] = -1; // Secondary skill if monster is immune to primary. Config.AttackSkill[6] = -1; // Secondary untimed skill if monster is immune to primary untimed. + // Low mana skills - these will be used if main skills can't be cast. + 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 + // Wereform setup. Make sure you read Templates/Attacks.txt for attack skill format. + Config.Wereform = false; // 0 / false - don't shapeshift, 1 / "Werewolf" - change to werewolf, 2 / "Werebear" - change to werebear + // Class specific config - Config.SummonRaven = true; + Config.SummonRaven = false; Config.SummonAnimal = "Grizzly"; // 0 = disabled, 1 or "Spirit Wolf" = summon spirit wolf, 2 or "Dire Wolf" = summon dire wolf, 3 or "Grizzly" = summon grizzly Config.SummonSpirit = "Oak Sage"; // 0 = disabled, 1 / "Oak Sage", 2 / "Heart of Wolverine", 3 / "Spirit of Barbs" Config.SummonVine = "Poison Creeper"; // 0 = disabled, 1 / "Poison Creeper", 2 / "Carrion Vine", 3 / "Solar Creeper" + + + // AutoBuild System ( See /d2bs/kolbot/libs/config/Builds/README.txt for instructions ) + Config.AutoBuild.Enabled = false; // This will enable or disable the AutoBuild system + + Config.AutoBuild.Template = "BuildName"; // The name of the build associated with an existing + // template filename located in libs/config/Builds/ + + Config.AutoBuild.Verbose = true; // Allows script to print messages in console + Config.AutoBuild.DebugMode = true; // Debug mode prints a little more information to console and + // logs activity to /logs/AutoBuild.CharacterName._MM_DD_YYYY.log + // It automatically enables Config.AutoBuild.Verbose } \ No newline at end of file diff --git a/d2bs/kolbot/libs/config/Necromancer.js b/d2bs/kolbot/libs/config/Necromancer.js index 896d361e5..6dbb616dc 100644 --- a/d2bs/kolbot/libs/config/Necromancer.js +++ b/d2bs/kolbot/libs/config/Necromancer.js @@ -20,6 +20,7 @@ function LoadConfig() { Scripts.BattleOrders = false; Config.BattleOrders.Mode = 0; // 0 = give BO, 1 = get BO Config.BattleOrders.Wait = false; // Idle until the player that received BO leaves. + Config.BattleOrders.Getters = []; // List of players to wait for before casting Battle Orders (mode 0). All players must be in the same area as the BOer. // Team MF system Config.MFLeader = false; // Set to true if you have one or more MFHelpers. Opens TP and gives commands when doing normal MF runs. @@ -34,8 +35,10 @@ function LoadConfig() { Config.Mausoleum.ClearCrypt = false; Scripts.Rakanishu = false; Config.Rakanishu.KillGriswold = true; + Scripts.UndergroundPassage = false; Scripts.Coldcrow = false; Scripts.Tristram = false; + Config.Tristram.PortalLeech = false; // Set to true to open a portal for leechers. Scripts.Pit = false; Config.Pit.ClearPit1 = true; Scripts.Treehead = false; @@ -48,26 +51,31 @@ function LoadConfig() { // *** act 2 *** Scripts.Radament = false; + Scripts.Coldworm = false; + Config.Coldworm.KillBeetleburst = false; + Config.Coldworm.ClearMaggotLair = false; // Clear all 3 levels Scripts.AncientTunnels = false; + Config.AncientTunnels.OpenChest = false; // Open special chest in Lost City + Config.AncientTunnels.KillDarkElder = false; Scripts.Summoner = false; + Config.Summoner.FireEye = false; Scripts.Tombs = false; Scripts.Duriel = false; // *** act 3 *** Scripts.Stormtree = false; - Scripts.KurastChests = false; - Config.KurastChests.LowerKurast = true; - Config.KurastChests.Bazaar = false; - Config.KurastChests.Sewers1 = false; - Config.KurastChests.Sewers2 = false; Scripts.KurastTemples = false; Scripts.Icehawk = false; Scripts.Endugu = false; Scripts.Travincal = false; + Config.Travincal.PortalLeech = false; // Set to true to open a portal for leechers. Scripts.Mephisto = false; Config.Mephisto.MoatTrick = false; + Config.Mephisto.KillCouncil = false; + Config.Mephisto.TakeRedPortal = true; // *** act 4 *** + Scripts.OuterSteppes = false; Scripts.Izual = false; Scripts.Hephasto = false; Scripts.Vizier = false; // Intended for classic sorc, kills Vizier only. @@ -77,9 +85,12 @@ function LoadConfig() { Config.Diablo.SealWarning = "Leave the seals alone!"; 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; + Config.Pindleskin.UseWaypoint = false; Config.Pindleskin.KillNihlathak = true; Config.Pindleskin.ViperQuit = false; // End script if Tomb Vipers are found. Scripts.Nihlathak = false; @@ -89,59 +100,133 @@ function LoadConfig() { Config.Eldritch.KillShenk = true; Config.Eldritch.KillDacFarren = true; Scripts.Eyeback = false; + Scripts.SharpTooth = false; Scripts.ThreshSocket = false; Scripts.Abaddon = false; Scripts.Frozenstein = false; Config.Frozenstein.ClearFrozenRiver = true; Scripts.Bonesaw = false; + Config.Bonesaw.ClearDrifterCavern = false; Scripts.Snapchip = false; Config.Snapchip.ClearIcyCellar = true; + Scripts.Worldstone = false; Scripts.Baal = false; - Config.Baal.HotTPMsg = "Hot TP!"; - Config.Baal.SafeTPMsg = "TP safe!"; - Config.Baal.BaalMsg = "Baal"; - Config.Baal.DollQuit = false; // End script if Dolls (Undead Soul Killers) are found. + Config.Baal.HotTPMessage = "Hot TP!"; + Config.Baal.SafeTPMessage = "Safe TP!"; + Config.Baal.BaalMessage = "Baal!"; + Config.Baal.SoulQuit = false; // End script if Souls (Undead Soul Killers) are found. + Config.Baal.DollQuit = false; // End script if Dolls (Undead Stigyan Dolls) are found. + Config.Baal.KillBaal = true; // Kill Baal. Leaves game after wave 5 if false. /* ### leeching section ### * Unless stated otherwise, leader's character name isn't needed on order to run. * Don't use more scripts of the same type! (Run AutoBaal OR BaalHelper, not both) */ + 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.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; // Find shrine when hot tp message is sent. You can change messages in AutoBaal.js + 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 + Config.AutoBaal.LongRangeSupport = false; // Cast long distance skills from a safe spot Scripts.BaalHelper = false; + Config.BaalHelper.Wait = 120; // Seconds to wait for a runner to be in Throne Config.BaalHelper.KillNihlathak = false; // Kill Nihlathak before going to Throne Config.BaalHelper.FastChaos = false; // Kill Diablo before going to Throne Config.BaalHelper.DollQuit = false; // End script if Dolls (Undead Soul Killers) are found. + Config.BaalHelper.KillBaal = true; // Kill Baal. If set to false, you must configure Config.QuitList or the bot will wait indefinitely. + Config.BaalHelper.SkipTP = false; // Don't wait for a TP, go to WSK3 and wait for someone to go to throne. Anti PK measure. Scripts.Follower = false; // Script that follows a manually played leader around like a merc. For a list of commands, see Follower.js - Config.Follower.Leader = ""; // Leader's ingame name. This only applies to Follower script - - Config.QuitList = []; // List of character names to quit with. Example: Config.QuitList = ["MySorc", "MyDin"]; // *** special scripts *** - Scripts.Rusher = false; // Rush bot alpha version (no questing yet, only rushing), for a list of commands, see Rusher.js + Scripts.WPGetter = false; // Get missing waypoints + Scripts.GetKeys = false; // Hunt for T/H/D keys + Scripts.OrgTorch = false; + Config.OrgTorch.MakeTorch = true; // Convert organ sets to torches + Config.OrgTorch.WaitForKeys = true; // Enable Torch System to get keys from other profiles. See libs/TorchSystem.js for more info + 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. 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). + 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.Trigger = ".chant"; + Config.Enchant.Triggers = ["chant", "cows", "wps"]; // Chat commands for enchant, cow level and waypoint giving + Config.Enchant.GetLeg = false; // Get Wirt's Leg from Tristram. If set to false, it will check for the leg in town. + Config.Enchant.AutoChant = false; // Automatically enchant nearby players and their minions Config.Enchant.GameLength = 20; // Game length in minutes 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, alpha version - Config.ShopBot.ShopNPC = "Anya"; // Only Anya for now - // 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.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 = [Areas.Act1.Cave_Level_2, Areas.Act1.Underground_Passage_Level_2, Areas.Act1.Hole_Level_2, Areas.Act1.Pit_Level_2, Areas.Act1.Crypt, Areas.Act1.Mausoleum]; // List of act 1 areas to open chests in + Config.ChestMania.Act2 = [Areas.Act2.Stony_Tomb_Level_1, Areas.Act2.Stony_Tomb_Level_2, Areas.Act2.Ancient_Tunnels, Areas.Act2.Tal_Rashas_Tomb_1, Areas.Act2.Tal_Rashas_Tomb_2, Areas.Act2.Tal_Rashas_Tomb_3, Areas.Act2.Tal_Rashas_Tomb_4, Areas.Act2.Tal_Rashas_Tomb_5, Areas.Act2.Tal_Rashas_Tomb_6, Areas.Act2.Tal_Rashas_Tomb_7]; // List of act 2 areas to open chests in + Config.ChestMania.Act3 = [Areas.Act3.Lower_Kurast, Areas.Act3.Kurast_Bazaar, Areas.Act3.Upper_Kurast, Areas.Act3.A3_Sewers_Level_1, Areas.Act3.A3_Sewers_Level_2, Areas.Act3.Spider_Cave, Areas.Act3.Spider_Cavern, Areas.Act3.Swampy_Pit_Level_3]; // List of act 3 areas to open chests in + Config.ChestMania.Act4 = []; // List of act 4 areas to open chests in + Config.ChestMania.Act5 = [Areas.Act5.Glacial_Trail, Areas.Act5.Drifter_Cavern, Areas.Act5.Icy_Cellar, Areas.Act5.Abaddon, Areas.Act5.Pit_Of_Acheron, Areas.Act5.Infernal_Pit]; // List of act 5 areas to open chests in + 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 (Enums Example: [Areas.Act1.Cave_Level_2, Areas.Act3.Kurast_Bazaar, Areas.Act5.Pit_Of_Acheron]; Ref. at https://pastebin.com/pRFkqDzb) + + + // *** Guest scripts *** + + // Baal Assistant by YourGreatestMember + Scripts.BaalAssistant = false; // Used to leech or help in baal runs. + Config.BaalAssistant.Wait = 120; // Seconds to wait for a runner to be in the throne / portal wait / safe TP wait / hot TP wait... + Config.BaalAssistant.KillNihlathak = false; // Kill Nihlathak before going to Throne + Config.BaalAssistant.FastChaos = false; // Kill Diablo before going to Throne + Config.BaalAssistant.Helper = true; // Set to true to help attack, set false to to leech. + Config.BaalAssistant.GetShrine = false; // Set to true to get a experience shrine at the start of the run. + Config.BaalAssistant.GetShrineWaitForHotTP = false; // Set to true to get a experience shrine after leader shouts the hot tp message as defined in Config.BaalAssistant.HotTPMessage + Config.BaalAssistant.SkipTP = false; // Set to true to enable the helper to skip the TP and teleport down to the throne room. + Config.BaalAssistant.WaitForSafeTP = false; // Set to true to wait for a safe TP message (defined in SafeTPMessage) + Config.BaalAssistant.DollQuit = false; // Quit on dolls. (Hardcore players?) + Config.BaalAssistant.SoulQuit = false; // Quit on Souls. (Hardcore players?) + Config.BaalAssistant.KillBaal = true; // Set to true to kill baal, if you set to false you MUST configure Config.QuitList or Config.BaalAssistant.NextGameMessage or the bot will wait indefinitely. + Config.BaalAssistant.HotTPMessage = ["Hot"]; // Configure safe TP messages. + Config.BaalAssistant.SafeTPMessage = ["Safe", "Clear"]; // Configure safe TP messages. + Config.BaalAssistant.BaalMessage = ["Baal"]; // Configure baal messages, this is a precautionary measure. + Config.BaalAssistant.NextGameMessage = ["Next Game", "Next", "New Game"]; // Next Game message, this is a precautionary quit command, Reccomended setting up: Config.QuitList // Town settings Config.HealHP = 50; // Go to a healer if under designated percent of life. Config.HealMP = 0; // Go to a healer if under designated percent of mana. + Config.HealStatus = false; // Go to a healer if poisoned or cursed Config.UseMerc = true; // Use merc. This is ignored and always false in d2classic. Config.MercWatch = false; // Instant merc revive during battle. @@ -152,6 +237,8 @@ function LoadConfig() { Config.UseRejuvMP = 0; // Drink a rejuvenation potion if mana is under designated percent. Config.UseMercHP = 75; // Give a healing potion to your merc if his/her life is under designated percent. Config.UseMercRejuv = 0; // Give a rejuvenation potion to your merc if his/her life is under designated percent. + Config.HPBuffer = 0; // Number of healing potions to keep in inventory. + Config.MPBuffer = 0; // Number of mana potions to keep in inventory. Config.RejuvBuffer = 0; // Number of rejuvenation potions to keep in inventory. // Chicken settings @@ -191,87 +278,156 @@ function LoadConfig() { Config.MinColumn[2] = 0; Config.MinColumn[3] = 0; - // Pickit config - Config.PickitFiles.push("kolton.nip"); // Pickit filenames in /pickit/ folder + // Pickit config. Default folder is kolbot/pickit. + Config.PickitFiles.push("kolton.nip"); Config.PickitFiles.push("LLD.nip"); Config.PickRange = 40; // Pick radius Config.FastPick = false; // Check and pick items between attacks + // 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. 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. + Config.RepairPercent = 40; // Durability percent of any equipped item that will trigger repairs. // Gambling config Config.Gamble = false; 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 - - // Cubing config. All recipes are available in Templates/Cubing.txt + + // 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. 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. - // All ingredients will be auto-picked, for classids check libs/NTItemAlias.dbl - 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 + // Ingredients for the following recipes will be auto-picked, for classids check libs/NTItemAlias.dbl + + //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]); // 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, "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, "Diadem"]); // Reroll magic Diadem + //Config.Recipes.push([Recipe.Reroll.Magic, "Grand Charm"]); // Reroll magic Grand Charm (ilvl 91+) - 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.Glove, 452]); // Craft Hit Power Vambraces + //Config.Recipes.push([Recipe.Reroll.Rare, "Diadem"]); // Reroll rare Diadem - Config.Recipes.push([Recipe.Reroll.Magic, 421]); // Reroll magic Diadem - Config.Recipes.push([Recipe.Reroll.Rare, 421]); // 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, "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 - // Base item must be in the pickit, rest is auto-picked - Config.Recipes.push([Recipe.Socket.Weapon, 255]); // Socket Thresher - Config.Recipes.push([Recipe.Socket.Weapon, 256]); // Socket Cryptic Axe - Config.Recipes.push([Recipe.Socket.Armor, 442]); // Socket Sacred Armor - Config.Recipes.push([Recipe.Socket.Armor, 443]); // Socket Archon Plate + //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 - * !!!NOTE!!! enhanced damage and enhanced defense on runewords are broken in the core right now * 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.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"); + //Config.KeepRunewords.push("[type] == shield || [type] == auricshields # [fcr] == 35"); - // General config - Config.PublicMode = 0; // 1 = invite, 2 = accept, 0 = disable - Config.LastMessage = ""; // Message to say at the end of the run. + // Public game options + + // If Config.Leader is set, the bot will only accept invites from leader. If Config.PublicMode is not 0, Baal and Diablo script will open Town Portals. + Config.PublicMode = 0; // 1 = invite and accept, 2 = accept only, 3 = invite only, 0 = disable + // Party message settings. Each setting represents an array of messages that will be randomly chosen. + // $name, $level, $class and $killer are replaced by the player's name, level, class and killer + Config.Greetings = []; // Example: ["Hello, $name (level $level $class)"] + 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.MinGameTime = 60; // Min game time in seconds. Bot will stay in game if the run is completed before. + 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. 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. + + // Shrine Scanner - scan for shrines while moving. + // Put the shrine types in order of priority (from highest to lowest). For a list of types, see sdk/shrines.txt + Config.ScanShrines = []; // Available Shrines: [Shrines.refilling, Shrines.health, Shrines.mana, Shrines.experience, Shrines.skill, Shrines.resist_lightning, Shrines.resist_fire, Shrines.armor, Shrines.combat, Shrines.resist_cold, Shrines.resist_poison, Shrines.mana_recharge, Shrines.stamina, Shrines.portal, Shrines.gem, Shrines.monster, Shrines.exploding, Shrines.poison]; + + // MF Switch + Config.MFSwitchPercent = 0; // Boss life % to switch weapons at. Set to 0 to disable. + Config.MFSwitch = 0; // MF weapon slot: 0 = slot I, 1 = slot II + + // Fastmod config + Config.FCR = 0; // 0 - disable, 1 to 255 - set value of faster cast rate + Config.FHR = 0; // 0 - disable, 1 to 255 - set value of faster hit recovery + 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 Config.HostileAction = 0; // 0 - quit immediately, 1 - quit when hostile player is sighted, 2 - attack hostile + Config.TownOnHostile = false; // Go to town instead of quitting when HostileAction is 0 or 1 + Config.RandomPrecast = false; // Anti-PK measure, only supported in Baal and BaalHelper and BaalAssisstant at the moment. + Config.ViperCheck = false; // Quit if revived Tomb Vipers are sighted // DClone config 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". @@ -286,6 +442,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 + * Example of Enums using: Config.AttackSkill[1] = Skills.Paladin.Blessed_Hammer; For Reference see https://pastebin.com/K7qCZw81 */ Config.AttackSkill[0] = -1; // Preattack skill. Config.AttackSkill[1] = -1; // Primary skill to bosses. @@ -295,10 +452,27 @@ function LoadConfig() { Config.AttackSkill[5] = -1; // Secondary skill if monster is immune to primary. Config.AttackSkill[6] = -1; // Secondary untimed skill if monster is immune to primary untimed. + // Low mana skills - these will be used if main skills can't be cast. + 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. 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 + + // Wereform setup. Make sure you read Templates/Attacks.txt for attack skill format. + Config.Wereform = false; // 0 / false - don't shapeshift, 1 / "Werewolf" - change to werewolf, 2 / "Werebear" - change to werebear // Class specific config Config.Curse[0] = 0; // Boss curse. Use skill number or set to 0 to disable. @@ -309,7 +483,20 @@ function LoadConfig() { Config.Skeletons = 0; // Number of skeletons to raise. Set to "max" to auto detect, set to 0 to disable. Config.SkeletonMages = 0; // Number of skeleton mages to raise. Set to "max" to auto detect, set to 0 to disable. Config.Revives = 0; // Number of revives to raise. Set to "max" to auto detect, set to 0 to disable. - Config.PoisonNovaDelay = 2000; // Delay between two Poison Novas + Config.PoisonNovaDelay = 2; // Delay between two Poison Novas in seconds. Config.ActiveSummon = false; // Raise dead between each attack. If false, it will raise after clearing a spot. Config.ReviveUnstackable = true; // Revive monsters that can move freely after you teleport. + Config.IronGolemChicken = 30; // Exit game if Iron Golem's life is less or equal to designated percent. + + + // AutoBuild System ( See /d2bs/kolbot/libs/config/Builds/README.txt for instructions ) + Config.AutoBuild.Enabled = false; // This will enable or disable the AutoBuild system + + Config.AutoBuild.Template = "BuildName"; // The name of the build associated with an existing + // template filename located in libs/config/Builds/ + + Config.AutoBuild.Verbose = true; // Allows script to print messages in console + Config.AutoBuild.DebugMode = true; // Debug mode prints a little more information to console and + // logs activity to /logs/AutoBuild.CharacterName._MM_DD_YYYY.log + // It automatically enables Config.AutoBuild.Verbose } \ No newline at end of file diff --git a/d2bs/kolbot/libs/config/Paladin.js b/d2bs/kolbot/libs/config/Paladin.js index cbc8b94d1..0ae534528 100644 --- a/d2bs/kolbot/libs/config/Paladin.js +++ b/d2bs/kolbot/libs/config/Paladin.js @@ -20,6 +20,7 @@ function LoadConfig() { Scripts.BattleOrders = false; Config.BattleOrders.Mode = 0; // 0 = give BO, 1 = get BO Config.BattleOrders.Wait = false; // Idle until the player that received BO leaves. + Config.BattleOrders.Getters = []; // List of players to wait for before casting Battle Orders (mode 0). All players must be in the same area as the BOer. // Team MF system Config.MFLeader = false; // Set to true if you have one or more MFHelpers. Opens TP and gives commands when doing normal MF runs. @@ -34,8 +35,10 @@ function LoadConfig() { Config.Mausoleum.ClearCrypt = false; Scripts.Rakanishu = false; Config.Rakanishu.KillGriswold = true; + Scripts.UndergroundPassage = false; Scripts.Coldcrow = false; Scripts.Tristram = false; + Config.Tristram.PortalLeech = false; // Set to true to open a portal for leechers. Scripts.Pit = false; Config.Pit.ClearPit1 = true; Scripts.Treehead = false; @@ -48,26 +51,31 @@ function LoadConfig() { // *** act 2 *** Scripts.Radament = false; + Scripts.Coldworm = false; + Config.Coldworm.KillBeetleburst = false; + Config.Coldworm.ClearMaggotLair = false; // Clear all 3 levels Scripts.AncientTunnels = false; + Config.AncientTunnels.OpenChest = false; // Open special chest in Lost City + Config.AncientTunnels.KillDarkElder = false; Scripts.Summoner = false; + Config.Summoner.FireEye = false; Scripts.Tombs = false; Scripts.Duriel = false; // *** act 3 *** Scripts.Stormtree = false; - Scripts.KurastChests = false; - Config.KurastChests.LowerKurast = true; - Config.KurastChests.Bazaar = false; - Config.KurastChests.Sewers1 = false; - Config.KurastChests.Sewers2 = false; Scripts.KurastTemples = false; Scripts.Icehawk = false; Scripts.Endugu = false; Scripts.Travincal = false; + Config.Travincal.PortalLeech = false; // Set to true to open a portal for leechers. Scripts.Mephisto = false; Config.Mephisto.MoatTrick = false; + Config.Mephisto.KillCouncil = false; + Config.Mephisto.TakeRedPortal = true; // *** act 4 *** + Scripts.OuterSteppes = false; Scripts.Izual = false; Scripts.Hephasto = false; Scripts.Vizier = false; // Intended for classic sorc, kills Vizier only. @@ -77,9 +85,12 @@ function LoadConfig() { Config.Diablo.SealWarning = "Leave the seals alone!"; 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; + Config.Pindleskin.UseWaypoint = false; Config.Pindleskin.KillNihlathak = true; Config.Pindleskin.ViperQuit = false; // End script if Tomb Vipers are found. Scripts.Nihlathak = false; @@ -89,59 +100,132 @@ function LoadConfig() { Config.Eldritch.KillShenk = true; Config.Eldritch.KillDacFarren = true; Scripts.Eyeback = false; + Scripts.SharpTooth = false; Scripts.ThreshSocket = false; Scripts.Abaddon = false; Scripts.Frozenstein = false; Config.Frozenstein.ClearFrozenRiver = true; Scripts.Bonesaw = false; + Config.Bonesaw.ClearDrifterCavern = false; Scripts.Snapchip = false; Config.Snapchip.ClearIcyCellar = true; + Scripts.Worldstone = false; Scripts.Baal = false; - Config.Baal.HotTPMsg = "Hot TP!"; - Config.Baal.SafeTPMsg = "TP safe!"; - Config.Baal.BaalMsg = "Baal"; - Config.Baal.DollQuit = false; // End script if Dolls (Undead Soul Killers) are found. + Config.Baal.HotTPMessage = "Hot TP!"; + Config.Baal.SafeTPMessage = "Safe TP!"; + Config.Baal.BaalMessage = "Baal!"; + Config.Baal.SoulQuit = false; // End script if Souls (Undead Soul Killers) are found. + Config.Baal.DollQuit = false; // End script if Dolls (Undead Stigyan Dolls) are found. + Config.Baal.KillBaal = true; // Kill Baal. Leaves game after wave 5 if false. /* ### leeching section ### * Unless stated otherwise, leader's character name isn't needed on order to run. * Don't use more scripts of the same type! (Run AutoBaal OR BaalHelper, not both) */ + 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.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; // Find shrine when hot tp message is sent. You can change messages in AutoBaal.js + 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 + Config.AutoBaal.LongRangeSupport = false; // Cast long distance skills from a safe spot Scripts.BaalHelper = false; + Config.BaalHelper.Wait = 120; // Seconds to wait for a runner to be in Throne Config.BaalHelper.KillNihlathak = false; // Kill Nihlathak before going to Throne Config.BaalHelper.FastChaos = false; // Kill Diablo before going to Throne Config.BaalHelper.DollQuit = false; // End script if Dolls (Undead Soul Killers) are found. + Config.BaalHelper.KillBaal = true; // Kill Baal. If set to false, you must configure Config.QuitList or the bot will wait indefinitely. + Config.BaalHelper.SkipTP = false; // Don't wait for a TP, go to WSK3 and wait for someone to go to throne. Anti PK measure. Scripts.Follower = false; // Script that follows a manually played leader around like a merc. For a list of commands, see Follower.js - Config.Follower.Leader = ""; // Leader's ingame name. This only applies to Follower script - - Config.QuitList = []; // List of character names to quit with. Example: Config.QuitList = ["MySorc", "MyDin"]; // *** special scripts *** - Scripts.Rusher = false; // Rush bot alpha version (no questing yet, only rushing), for a list of commands, see Rusher.js + Scripts.WPGetter = false; // Get missing waypoints + Scripts.GetKeys = false; // Hunt for T/H/D keys + Scripts.OrgTorch = false; + Config.OrgTorch.MakeTorch = true; // Convert organ sets to torches + Config.OrgTorch.WaitForKeys = true; // Enable Torch System to get keys from other profiles. See libs/TorchSystem.js for more info + 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. 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). + 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.Trigger = ".chant"; + Config.Enchant.Triggers = ["chant", "cows", "wps"]; // Chat commands for enchant, cow level and waypoint giving + Config.Enchant.GetLeg = false; // Get Wirt's Leg from Tristram. If set to false, it will check for the leg in town. + Config.Enchant.AutoChant = false; // Automatically enchant nearby players and their minions Config.Enchant.GameLength = 20; // Game length in minutes 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, alpha version - Config.ShopBot.ShopNPC = "Anya"; // Only Anya for now - // 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.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 = [Areas.Act1.Cave_Level_2, Areas.Act1.Underground_Passage_Level_2, Areas.Act1.Hole_Level_2, Areas.Act1.Pit_Level_2, Areas.Act1.Crypt, Areas.Act1.Mausoleum]; // List of act 1 areas to open chests in + Config.ChestMania.Act2 = [Areas.Act2.Stony_Tomb_Level_1, Areas.Act2.Stony_Tomb_Level_2, Areas.Act2.Ancient_Tunnels, Areas.Act2.Tal_Rashas_Tomb_1, Areas.Act2.Tal_Rashas_Tomb_2, Areas.Act2.Tal_Rashas_Tomb_3, Areas.Act2.Tal_Rashas_Tomb_4, Areas.Act2.Tal_Rashas_Tomb_5, Areas.Act2.Tal_Rashas_Tomb_6, Areas.Act2.Tal_Rashas_Tomb_7]; // List of act 2 areas to open chests in + Config.ChestMania.Act3 = [Areas.Act3.Lower_Kurast, Areas.Act3.Kurast_Bazaar, Areas.Act3.Upper_Kurast, Areas.Act3.A3_Sewers_Level_1, Areas.Act3.A3_Sewers_Level_2, Areas.Act3.Spider_Cave, Areas.Act3.Spider_Cavern, Areas.Act3.Swampy_Pit_Level_3]; // List of act 3 areas to open chests in + Config.ChestMania.Act4 = []; // List of act 4 areas to open chests in + Config.ChestMania.Act5 = [Areas.Act5.Glacial_Trail, Areas.Act5.Drifter_Cavern, Areas.Act5.Icy_Cellar, Areas.Act5.Abaddon, Areas.Act5.Pit_Of_Acheron, Areas.Act5.Infernal_Pit]; // List of act 5 areas to open chests in + 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 (Enums Example: [Areas.Act1.Cave_Level_2, Areas.Act3.Kurast_Bazaar, Areas.Act5.Pit_Of_Acheron]; Ref. at https://pastebin.com/pRFkqDzb) + + // *** Guest scripts *** + + // Baal Assistant by YourGreatestMember + Scripts.BaalAssistant = false; // Used to leech or help in baal runs. + Config.BaalAssistant.Wait = 120; // Seconds to wait for a runner to be in the throne / portal wait / safe TP wait / hot TP wait... + Config.BaalAssistant.KillNihlathak = false; // Kill Nihlathak before going to Throne + Config.BaalAssistant.FastChaos = false; // Kill Diablo before going to Throne + Config.BaalAssistant.Helper = true; // Set to true to help attack, set false to to leech. + Config.BaalAssistant.GetShrine = false; // Set to true to get a experience shrine at the start of the run. + Config.BaalAssistant.GetShrineWaitForHotTP = false; // Set to true to get a experience shrine after leader shouts the hot tp message as defined in Config.BaalAssistant.HotTPMessage + Config.BaalAssistant.SkipTP = false; // Set to true to enable the helper to skip the TP and teleport down to the throne room. + Config.BaalAssistant.WaitForSafeTP = false; // Set to true to wait for a safe TP message (defined in SafeTPMessage) + Config.BaalAssistant.DollQuit = false; // Quit on dolls. (Hardcore players?) + Config.BaalAssistant.SoulQuit = false; // Quit on Souls. (Hardcore players?) + Config.BaalAssistant.KillBaal = true; // Set to true to kill baal, if you set to false you MUST configure Config.QuitList or Config.BaalAssistant.NextGameMessage or the bot will wait indefinitely. + Config.BaalAssistant.HotTPMessage = ["Hot"]; // Configure safe TP messages. + Config.BaalAssistant.SafeTPMessage = ["Safe", "Clear"]; // Configure safe TP messages. + Config.BaalAssistant.BaalMessage = ["Baal"]; // Configure baal messages, this is a precautionary measure. + Config.BaalAssistant.NextGameMessage = ["Next Game", "Next", "New Game"]; // Next Game message, this is a precautionary quit command, Reccomended setting up: Config.QuitList // Town settings Config.HealHP = 50; // Go to a healer if under designated percent of life. Config.HealMP = 0; // Go to a healer if under designated percent of mana. + Config.HealStatus = false; // Go to a healer if poisoned or cursed Config.UseMerc = true; // Use merc. This is ignored and always false in d2classic. Config.MercWatch = false; // Instant merc revive during battle. @@ -152,6 +236,8 @@ function LoadConfig() { Config.UseRejuvMP = 0; // Drink a rejuvenation potion if mana is under designated percent. Config.UseMercHP = 75; // Give a healing potion to your merc if his/her life is under designated percent. Config.UseMercRejuv = 0; // Give a rejuvenation potion to your merc if his/her life is under designated percent. + Config.HPBuffer = 0; // Number of healing potions to keep in inventory. + Config.MPBuffer = 0; // Number of mana potions to keep in inventory. Config.RejuvBuffer = 0; // Number of rejuvenation potions to keep in inventory. // Chicken settings @@ -191,87 +277,156 @@ function LoadConfig() { Config.MinColumn[2] = 0; Config.MinColumn[3] = 0; - // Pickit config - Config.PickitFiles.push("kolton.nip"); // Pickit filenames in /pickit/ folder + // Pickit config. Default folder is kolbot/pickit. + Config.PickitFiles.push("kolton.nip"); Config.PickitFiles.push("LLD.nip"); Config.PickRange = 40; // Pick radius Config.FastPick = false; // Check and pick items between attacks + // 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. 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. + Config.RepairPercent = 40; // Durability percent of any equipped item that will trigger repairs. // Gambling config Config.Gamble = false; 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 - - // Cubing config. All recipes are available in Templates/Cubing.txt + + // 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. 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. - // All ingredients will be auto-picked, for classids check libs/NTItemAlias.dbl - 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 + // Ingredients for the following recipes will be auto-picked, for classids check libs/NTItemAlias.dbl + + //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]); // 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.Glove, 452]); // Craft Hit Power Vambraces + //Config.Recipes.push([Recipe.Caster.Amulet]); // Craft Caster Amulet + //Config.Recipes.push([Recipe.Blood.Ring]); // Craft Blood Ring + //Config.Recipes.push([Recipe.Blood.Helm, "Armet"]); // Craft Blood Armet + //Config.Recipes.push([Recipe.HitPower.Gloves, "Vambraces"]); // Craft Hit Power Vambraces - Config.Recipes.push([Recipe.Reroll.Magic, 421]); // Reroll magic Diadem - Config.Recipes.push([Recipe.Reroll.Rare, 421]); // Reroll rare Diadem + // The gems not used by other recipes will be used for magic item rerolling. + + //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, "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, "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 - // Base item must be in the pickit, rest is auto-picked - Config.Recipes.push([Recipe.Socket.Weapon, 255]); // Socket Thresher - Config.Recipes.push([Recipe.Socket.Weapon, 256]); // Socket Cryptic Axe - Config.Recipes.push([Recipe.Socket.Armor, 442]); // Socket Sacred Armor - Config.Recipes.push([Recipe.Socket.Armor, 443]); // Socket Archon Plate + //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 - * !!!NOTE!!! enhanced damage and enhanced defense on runewords are broken in the core right now * 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.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"); + //Config.KeepRunewords.push("[type] == shield || [type] == auricshields # [fcr] == 35"); - // General config - Config.PublicMode = 0; // 1 = invite, 2 = accept, 0 = disable - Config.LastMessage = ""; // Message to say at the end of the run. + // Public game options + + // If Config.Leader is set, the bot will only accept invites from leader. If Config.PublicMode is not 0, Baal and Diablo script will open Town Portals. + Config.PublicMode = 0; // 1 = invite and accept, 2 = accept only, 3 = invite only, 0 = disable + // Party message settings. Each setting represents an array of messages that will be randomly chosen. + // $name, $level, $class and $killer are replaced by the player's name, level, class and killer + Config.Greetings = []; // Example: ["Hello, $name (level $level $class)"] + 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.MinGameTime = 60; // Min game time in seconds. Bot will stay in game if the run is completed before. + 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. 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. + + // Shrine Scanner - scan for shrines while moving. + // Put the shrine types in order of priority (from highest to lowest). For a list of types, see sdk/shrines.txt + Config.ScanShrines = []; // Available Shrines: [Shrines.refilling, Shrines.health, Shrines.mana, Shrines.experience, Shrines.skill, Shrines.resist_lightning, Shrines.resist_fire, Shrines.armor, Shrines.combat, Shrines.resist_cold, Shrines.resist_poison, Shrines.mana_recharge, Shrines.stamina, Shrines.portal, Shrines.gem, Shrines.monster, Shrines.exploding, Shrines.poison]; + + // MF Switch + Config.MFSwitchPercent = 0; // Boss life % to switch weapons at. Set to 0 to disable. + Config.MFSwitch = 0; // MF weapon slot: 0 = slot I, 1 = slot II + + // Fastmod config + Config.FCR = 0; // 0 - disable, 1 to 255 - set value of faster cast rate + Config.FHR = 0; // 0 - disable, 1 to 255 - set value of faster hit recovery + 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 Config.HostileAction = 0; // 0 - quit immediately, 1 - quit when hostile player is sighted, 2 - attack hostile + Config.TownOnHostile = false; // Go to town instead of quitting when HostileAction is 0 or 1 + Config.RandomPrecast = false; // Anti-PK measure, only supported in Baal and BaalHelper and BaalAssisstant at the moment. + Config.ViperCheck = false; // Quit if revived Tomb Vipers are sighted // DClone config 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". @@ -286,6 +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 + * Example of Enums using: Config.AttackSkill[1] = Skills.Paladin.Blessed_Hammer; For Reference see https://pastebin.com/K7qCZw81 */ Config.AttackSkill[0] = -1; // Preattack skill. Config.AttackSkill[1] = -1; // Primary skill to bosses. @@ -295,11 +451,39 @@ function LoadConfig() { Config.AttackSkill[5] = -1; // Secondary skill if monster is immune to primary. Config.AttackSkill[6] = -1; // Secondary aura. + // Low mana skills - these will be used if main skills can't be cast. + 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 + // Wereform setup. Make sure you read Templates/Attacks.txt for attack skill format. + Config.Wereform = false; // 0 / false - don't shapeshift, 1 / "Werewolf" - change to werewolf, 2 / "Werebear" - change to werebear + // 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] + + + // AutoBuild System ( See /d2bs/kolbot/libs/config/Builds/README.txt for instructions ) + Config.AutoBuild.Enabled = false; // This will enable or disable the AutoBuild system + + Config.AutoBuild.Template = "BuildName"; // The name of the build associated with an existing + // template filename located in libs/config/Builds/ + + Config.AutoBuild.Verbose = true; // Allows script to print messages in console + Config.AutoBuild.DebugMode = true; // Debug mode prints a little more information to console and + // logs activity to /logs/AutoBuild.CharacterName._MM_DD_YYYY.log + // It automatically enables Config.AutoBuild.Verbose } \ No newline at end of file diff --git a/d2bs/kolbot/libs/config/Sorceress.js b/d2bs/kolbot/libs/config/Sorceress.js index 20f9ea80d..425d1bdba 100644 --- a/d2bs/kolbot/libs/config/Sorceress.js +++ b/d2bs/kolbot/libs/config/Sorceress.js @@ -20,6 +20,7 @@ function LoadConfig() { Scripts.BattleOrders = false; Config.BattleOrders.Mode = 0; // 0 = give BO, 1 = get BO Config.BattleOrders.Wait = false; // Idle until the player that received BO leaves. + Config.BattleOrders.Getters = []; // List of players to wait for before casting Battle Orders (mode 0). All players must be in the same area as the BOer. // Team MF system Config.MFLeader = false; // Set to true if you have one or more MFHelpers. Opens TP and gives commands when doing normal MF runs. @@ -34,8 +35,10 @@ function LoadConfig() { Config.Mausoleum.ClearCrypt = false; Scripts.Rakanishu = false; Config.Rakanishu.KillGriswold = true; + Scripts.UndergroundPassage = false; Scripts.Coldcrow = false; Scripts.Tristram = false; + Config.Tristram.PortalLeech = false; // Set to true to open a portal for leechers. Scripts.Pit = false; Config.Pit.ClearPit1 = true; Scripts.Treehead = false; @@ -48,26 +51,31 @@ function LoadConfig() { // *** act 2 *** Scripts.Radament = false; + Scripts.Coldworm = false; + Config.Coldworm.KillBeetleburst = false; + Config.Coldworm.ClearMaggotLair = false; // Clear all 3 levels Scripts.AncientTunnels = false; + Config.AncientTunnels.OpenChest = false; // Open special chest in Lost City + Config.AncientTunnels.KillDarkElder = false; Scripts.Summoner = false; + Config.Summoner.FireEye = false; Scripts.Tombs = false; Scripts.Duriel = false; // *** act 3 *** Scripts.Stormtree = false; - Scripts.KurastChests = false; - Config.KurastChests.LowerKurast = true; - Config.KurastChests.Bazaar = false; - Config.KurastChests.Sewers1 = false; - Config.KurastChests.Sewers2 = false; Scripts.KurastTemples = false; Scripts.Icehawk = false; Scripts.Endugu = false; Scripts.Travincal = false; + Config.Travincal.PortalLeech = false; // Set to true to open a portal for leechers. Scripts.Mephisto = false; Config.Mephisto.MoatTrick = false; + Config.Mephisto.KillCouncil = false; + Config.Mephisto.TakeRedPortal = true; // *** act 4 *** + Scripts.OuterSteppes = false; Scripts.Izual = false; Scripts.Hephasto = false; Scripts.Vizier = false; // Intended for classic sorc, kills Vizier only. @@ -77,9 +85,12 @@ function LoadConfig() { Config.Diablo.SealWarning = "Leave the seals alone!"; 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; + Config.Pindleskin.UseWaypoint = false; Config.Pindleskin.KillNihlathak = true; Config.Pindleskin.ViperQuit = false; // End script if Tomb Vipers are found. Scripts.Nihlathak = false; @@ -89,59 +100,132 @@ function LoadConfig() { Config.Eldritch.KillShenk = true; Config.Eldritch.KillDacFarren = true; Scripts.Eyeback = false; + Scripts.SharpTooth = false; Scripts.ThreshSocket = false; Scripts.Abaddon = false; Scripts.Frozenstein = false; Config.Frozenstein.ClearFrozenRiver = true; Scripts.Bonesaw = false; + Config.Bonesaw.ClearDrifterCavern = false; Scripts.Snapchip = false; Config.Snapchip.ClearIcyCellar = true; + Scripts.Worldstone = false; Scripts.Baal = false; - Config.Baal.HotTPMsg = "Hot TP!"; - Config.Baal.SafeTPMsg = "TP safe!"; - Config.Baal.BaalMsg = "Baal"; - Config.Baal.DollQuit = false; // End script if Dolls (Undead Soul Killers) are found. + Config.Baal.HotTPMessage = "Hot TP!"; + Config.Baal.SafeTPMessage = "Safe TP!"; + Config.Baal.BaalMessage = "Baal!"; + Config.Baal.SoulQuit = false; // End script if Souls (Undead Soul Killers) are found. + Config.Baal.DollQuit = false; // End script if Dolls (Undead Stigyan Dolls) are found. + Config.Baal.KillBaal = true; // Kill Baal. Leaves game after wave 5 if false. /* ### leeching section ### * Unless stated otherwise, leader's character name isn't needed on order to run. * Don't use more scripts of the same type! (Run AutoBaal OR BaalHelper, not both) */ + 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.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; // Find shrine when hot tp message is sent. You can change messages in AutoBaal.js + 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 + Config.AutoBaal.LongRangeSupport = false; // Cast long distance skills from a safe spot Scripts.BaalHelper = false; + Config.BaalHelper.Wait = 120; // Seconds to wait for a runner to be in Throne Config.BaalHelper.KillNihlathak = false; // Kill Nihlathak before going to Throne Config.BaalHelper.FastChaos = false; // Kill Diablo before going to Throne Config.BaalHelper.DollQuit = false; // End script if Dolls (Undead Soul Killers) are found. + Config.BaalHelper.KillBaal = true; // Kill Baal. If set to false, you must configure Config.QuitList or the bot will wait indefinitely. + Config.BaalHelper.SkipTP = false; // Don't wait for a TP, go to WSK3 and wait for someone to go to throne. Anti PK measure. Scripts.Follower = false; // Script that follows a manually played leader around like a merc. For a list of commands, see Follower.js - Config.Follower.Leader = ""; // Leader's ingame name. This only applies to Follower script - - Config.QuitList = []; // List of character names to quit with. Example: Config.QuitList = ["MySorc", "MyDin"]; // *** special scripts *** - Scripts.Rusher = false; // Rush bot alpha version (no questing yet, only rushing), for a list of commands, see Rusher.js + Scripts.WPGetter = false; // Get missing waypoints + Scripts.GetKeys = false; // Hunt for T/H/D keys + Scripts.OrgTorch = false; + Config.OrgTorch.MakeTorch = true; // Convert organ sets to torches + Config.OrgTorch.WaitForKeys = true; // Enable Torch System to get keys from other profiles. See libs/TorchSystem.js for more info + 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. 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). + 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.Trigger = ".chant"; + Config.Enchant.Triggers = ["chant", "cows", "wps"]; // Chat commands for enchant, cow level and waypoint giving + Config.Enchant.GetLeg = false; // Get Wirt's Leg from Tristram. If set to false, it will check for the leg in town. + Config.Enchant.AutoChant = false; // Automatically enchant nearby players and their minions Config.Enchant.GameLength = 20; // Game length in minutes 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, alpha version - Config.ShopBot.ShopNPC = "Anya"; // Only Anya for now - // 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.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 = [Areas.Act1.Cave_Level_2, Areas.Act1.Underground_Passage_Level_2, Areas.Act1.Hole_Level_2, Areas.Act1.Pit_Level_2, Areas.Act1.Crypt, Areas.Act1.Mausoleum]; // List of act 1 areas to open chests in + Config.ChestMania.Act2 = [Areas.Act2.Stony_Tomb_Level_1, Areas.Act2.Stony_Tomb_Level_2, Areas.Act2.Ancient_Tunnels, Areas.Act2.Tal_Rashas_Tomb_1, Areas.Act2.Tal_Rashas_Tomb_2, Areas.Act2.Tal_Rashas_Tomb_3, Areas.Act2.Tal_Rashas_Tomb_4, Areas.Act2.Tal_Rashas_Tomb_5, Areas.Act2.Tal_Rashas_Tomb_6, Areas.Act2.Tal_Rashas_Tomb_7]; // List of act 2 areas to open chests in + Config.ChestMania.Act3 = [Areas.Act3.Lower_Kurast, Areas.Act3.Kurast_Bazaar, Areas.Act3.Upper_Kurast, Areas.Act3.A3_Sewers_Level_1, Areas.Act3.A3_Sewers_Level_2, Areas.Act3.Spider_Cave, Areas.Act3.Spider_Cavern, Areas.Act3.Swampy_Pit_Level_3]; // List of act 3 areas to open chests in + Config.ChestMania.Act4 = []; // List of act 4 areas to open chests in + Config.ChestMania.Act5 = [Areas.Act5.Glacial_Trail, Areas.Act5.Drifter_Cavern, Areas.Act5.Icy_Cellar, Areas.Act5.Abaddon, Areas.Act5.Pit_Of_Acheron, Areas.Act5.Infernal_Pit]; // List of act 5 areas to open chests in + 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 (Enums Example: [Areas.Act1.Cave_Level_2, Areas.Act3.Kurast_Bazaar, Areas.Act5.Pit_Of_Acheron]; Ref. at https://pastebin.com/pRFkqDzb) + + // *** Guest scripts *** + + // Baal Assistant by YourGreatestMember + Scripts.BaalAssistant = false; // Used to leech or help in baal runs. + Config.BaalAssistant.Wait = 120; // Seconds to wait for a runner to be in the throne / portal wait / safe TP wait / hot TP wait... + Config.BaalAssistant.KillNihlathak = false; // Kill Nihlathak before going to Throne + Config.BaalAssistant.FastChaos = false; // Kill Diablo before going to Throne + Config.BaalAssistant.Helper = true; // Set to true to help attack, set false to to leech. + Config.BaalAssistant.GetShrine = false; // Set to true to get a experience shrine at the start of the run. + Config.BaalAssistant.GetShrineWaitForHotTP = false; // Set to true to get a experience shrine after leader shouts the hot tp message as defined in Config.BaalAssistant.HotTPMessage + Config.BaalAssistant.SkipTP = false; // Set to true to enable the helper to skip the TP and teleport down to the throne room. + Config.BaalAssistant.WaitForSafeTP = false; // Set to true to wait for a safe TP message (defined in SafeTPMessage) + Config.BaalAssistant.DollQuit = false; // Quit on dolls. (Hardcore players?) + Config.BaalAssistant.SoulQuit = false; // Quit on Souls. (Hardcore players?) + Config.BaalAssistant.KillBaal = true; // Set to true to kill baal, if you set to false you MUST configure Config.QuitList or Config.BaalAssistant.NextGameMessage or the bot will wait indefinitely. + Config.BaalAssistant.HotTPMessage = ["Hot"]; // Configure safe TP messages. + Config.BaalAssistant.SafeTPMessage = ["Safe", "Clear"]; // Configure safe TP messages. + Config.BaalAssistant.BaalMessage = ["Baal"]; // Configure baal messages, this is a precautionary measure. + Config.BaalAssistant.NextGameMessage = ["Next Game", "Next", "New Game"]; // Next Game message, this is a precautionary quit command, Reccomended setting up: Config.QuitList // Town settings Config.HealHP = 50; // Go to a healer if under designated percent of life. Config.HealMP = 0; // Go to a healer if under designated percent of mana. + Config.HealStatus = false; // Go to a healer if poisoned or cursed Config.UseMerc = true; // Use merc. This is ignored and always false in d2classic. Config.MercWatch = false; // Instant merc revive during battle. @@ -152,6 +236,8 @@ function LoadConfig() { Config.UseRejuvMP = 0; // Drink a rejuvenation potion if mana is under designated percent. Config.UseMercHP = 75; // Give a healing potion to your merc if his/her life is under designated percent. Config.UseMercRejuv = 0; // Give a rejuvenation potion to your merc if his/her life is under designated percent. + Config.HPBuffer = 0; // Number of healing potions to keep in inventory. + Config.MPBuffer = 0; // Number of mana potions to keep in inventory. Config.RejuvBuffer = 0; // Number of rejuvenation potions to keep in inventory. // Chicken settings @@ -191,87 +277,156 @@ function LoadConfig() { Config.MinColumn[2] = 0; Config.MinColumn[3] = 0; - // Pickit config - Config.PickitFiles.push("kolton.nip"); // Pickit filenames in /pickit/ folder + // Pickit config. Default folder is kolbot/pickit. + Config.PickitFiles.push("kolton.nip"); Config.PickitFiles.push("LLD.nip"); Config.PickRange = 40; // Pick radius Config.FastPick = false; // Check and pick items between attacks + // 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. 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. + Config.RepairPercent = 40; // Durability percent of any equipped item that will trigger repairs. // Gambling config Config.Gamble = false; 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 - - // Cubing config. All recipes are available in Templates/Cubing.txt + + // 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. 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. - // All ingredients will be auto-picked, for classids check libs/NTItemAlias.dbl - 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 + // Ingredients for the following recipes will be auto-picked, for classids check libs/NTItemAlias.dbl + + //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]); // 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.Glove, 452]); // Craft Hit Power Vambraces + //Config.Recipes.push([Recipe.Caster.Amulet]); // Craft Caster Amulet + //Config.Recipes.push([Recipe.Blood.Ring]); // Craft Blood Ring + //Config.Recipes.push([Recipe.Blood.Helm, "Armet"]); // Craft Blood Armet + //Config.Recipes.push([Recipe.HitPower.Gloves, "Vambraces"]); // Craft Hit Power Vambraces - Config.Recipes.push([Recipe.Reroll.Magic, 421]); // Reroll magic Diadem - Config.Recipes.push([Recipe.Reroll.Rare, 421]); // Reroll rare Diadem + // The gems not used by other recipes will be used for magic item rerolling. + + //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, "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, "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 - // Base item must be in the pickit, rest is auto-picked - Config.Recipes.push([Recipe.Socket.Weapon, 255]); // Socket Thresher - Config.Recipes.push([Recipe.Socket.Weapon, 256]); // Socket Cryptic Axe - Config.Recipes.push([Recipe.Socket.Armor, 442]); // Socket Sacred Armor - Config.Recipes.push([Recipe.Socket.Armor, 443]); // Socket Archon Plate + //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 - * !!!NOTE!!! enhanced damage and enhanced defense on runewords are broken in the core right now * 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.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"); + //Config.KeepRunewords.push("[type] == shield || [type] == auricshields # [fcr] == 35"); - // General config - Config.PublicMode = 0; // 1 = invite, 2 = accept, 0 = disable - Config.LastMessage = ""; // Message to say at the end of the run. + // Public game options + + // If Config.Leader is set, the bot will only accept invites from leader. If Config.PublicMode is not 0, Baal and Diablo script will open Town Portals. + Config.PublicMode = 0; // 1 = invite and accept, 2 = accept only, 3 = invite only, 0 = disable + // Party message settings. Each setting represents an array of messages that will be randomly chosen. + // $name, $level, $class and $killer are replaced by the player's name, level, class and killer + Config.Greetings = []; // Example: ["Hello, $name (level $level $class)"] + 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.MinGameTime = 60; // Min game time in seconds. Bot will stay in game if the run is completed before. + 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. 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. + + // Shrine Scanner - scan for shrines while moving. + // Put the shrine types in order of priority (from highest to lowest). For a list of types, see sdk/shrines.txt + Config.ScanShrines = []; // Available Shrines: [Shrines.refilling, Shrines.health, Shrines.mana, Shrines.experience, Shrines.skill, Shrines.resist_lightning, Shrines.resist_fire, Shrines.armor, Shrines.combat, Shrines.resist_cold, Shrines.resist_poison, Shrines.mana_recharge, Shrines.stamina, Shrines.portal, Shrines.gem, Shrines.monster, Shrines.exploding, Shrines.poison]; + + // MF Switch + Config.MFSwitchPercent = 0; // Boss life % to switch weapons at. Set to 0 to disable. + Config.MFSwitch = 0; // MF weapon slot: 0 = slot I, 1 = slot II + + // Speedup config. Full packet casting is not recommended for melee skills. + Config.FCR = 0; // 0 - disable, 1 to 255 - set value of Faster Cast Rate. + Config.FHR = 0; // 0 - disable, 1 to 255 - set value of Faster Hit Recovery. + 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 - Config.HostileAction = 0; // 0 - quit immediately, 1 - quit when hostile player is sighted, 2 - attack hostile + Config.AntiHostile = false; // Enable anti-hostile. + Config.HostileAction = 0; // 0 - quit immediately, 1 - quit when hostile player is sighted, 2 - attack hostile. + Config.TownOnHostile = false; // Go to town instead of quitting when HostileAction is 0 or 1. + Config.RandomPrecast = false; // Anti-PK measure, only supported in Baal and BaalHelper and BaalAssisstant at the moment. + Config.ViperCheck = false; // Quit if revived Tomb Vipers are sighted. // DClone config 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". @@ -286,6 +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 + * Example of Enums using: Config.AttackSkill[1] = Skills.Paladin.Blessed_Hammer; For Reference see https://pastebin.com/K7qCZw81 */ Config.AttackSkill[0] = -1; // Preattack skill. Config.AttackSkill[1] = -1; // Primary skill to bosses. @@ -295,12 +451,42 @@ function LoadConfig() { Config.AttackSkill[5] = -1; // Secondary skill if monster is immune to primary. Config.AttackSkill[6] = -1; // Secondary untimed skill if monster is immune to primary untimed. - Config.Dodge = false; // Move away from monsters that get too close. Don't use with short-ranged attacks like Nova. + // Low mana skills - these will be used if main skills can't be cast. + 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. 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 + // Wereform setup. Make sure you read Templates/Attacks.txt for attack skill format. + Config.Wereform = false; // 0 / false - don't shapeshift, 1 / "Werewolf" - change to werewolf, 2 / "Werebear" - change to werebear + // 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 ) + Config.AutoBuild.Enabled = false; // This will enable or disable the AutoBuild system + + Config.AutoBuild.Template = "BuildName"; // The name of the build associated with an existing + // template filename located in libs/config/Builds/ + + Config.AutoBuild.Verbose = true; // Allows script to print messages in console + Config.AutoBuild.DebugMode = true; // Debug mode prints a little more information to console and + // logs activity to /logs/AutoBuild.CharacterName._MM_DD_YYYY.log + // It automatically enables Config.AutoBuild.Verbose } \ No newline at end of file diff --git a/d2bs/kolbot/libs/config/Templates/Attacks.txt b/d2bs/kolbot/libs/config/Templates/Attacks.txt index 9f2ef8537..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. @@ -184,14 +184,14 @@ *** Charge-up martial skills aren't supported, there's no way to determine charge-up state -*** Trap assassin using lightning sentry, death sentry as traps, shock web as timed attack and fire blast as untimed attack +*** Trap assassin using lightning sentry and death sentry as traps, shock web as timed attack and fire blast as untimed attack Config.AttackSkill[0] = -1; // Preattack skill. Not implemented yet. Config.AttackSkill[1] = 256; // Primary skill to bosses. Config.AttackSkill[2] = 251; // Primary untimed skill to bosses. Keep at -1 if Config.AttackSkill[1] is untimed skill. Config.AttackSkill[3] = 256; // Primary skill to others. Config.AttackSkill[4] = 251; // Primary untimed skill to bosses. Keep at -1 if Config.AttackSkill[3] is untimed skill. - Config.AttackSkill[5] = -1; // Secondary skill if monster is immune to primary. + Config.AttackSkill[5] = 251; // Secondary skill if monster is immune to primary. Config.AttackSkill[6] = -1; // Secondary untimed skill if monster is immune to primary untimed. // Class specific config @@ -213,3 +213,56 @@ Config.UseTraps = true; Config.Traps = [262, 262, 262, 262, 262]; Config.BossTraps = [262, 262, 262, 262, 262]; + +*** Kicksin using Death Sentry for traps + + Config.AttackSkill[0] = -1; // Preattack skill. Not implemented yet. + Config.AttackSkill[1] = 255; // Primary skill to bosses. + Config.AttackSkill[2] = -1; // Primary untimed skill to bosses. Keep at -1 if Config.AttackSkill[1] is untimed skill. + Config.AttackSkill[3] = 255; // Primary skill to others. + Config.AttackSkill[4] = -1; // Primary untimed skill to bosses. Keep at -1 if Config.AttackSkill[3] is untimed skill. + Config.AttackSkill[5] = -1; // Secondary skill if monster is immune to primary. + Config.AttackSkill[6] = -1; // Secondary untimed skill if monster is immune to primary untimed. + + // Class specific config + Config.UseTraps = true; + Config.Traps = [276, 276, 276, 276, 276]; + Config.BossTraps = [276, 276, 276, 276, 276]; + +################## +#### WEREFORM #### +################## + +*** Wereform attacks use the Barbarian attack format + +*** Fury/Rabies + + Config.AttackSkill[0] = -1; // Preattack skill. + Config.AttackSkill[1] = 248; // Primary skill for bosses. + Config.AttackSkill[2] = 238; // Backup/Immune skill for bosses. + Config.AttackSkill[3] = 248; // Primary skill for others. + Config.AttackSkill[4] = 238; // Backup/Immune skill for others. + +*** Fire Claws + + Config.AttackSkill[0] = -1; // Preattack skill. + Config.AttackSkill[1] = 239; // Primary skill for bosses. + Config.AttackSkill[2] = -1; // Backup/Immune skill for bosses. + Config.AttackSkill[3] = 239; // Primary skill for others. + Config.AttackSkill[4] = -1; // Backup/Immune skill for others. + +*** Feral Rage + + Config.AttackSkill[0] = -1; // Preattack skill. + Config.AttackSkill[1] = 232; // Primary skill for bosses. + Config.AttackSkill[2] = -1; // Backup/Immune skill for bosses. + Config.AttackSkill[3] = 232; // Primary skill for others. + Config.AttackSkill[4] = -1; // Backup/Immune skill for others. + +*** Normal attack + + Config.AttackSkill[0] = -1; // Preattack skill. + Config.AttackSkill[1] = 0; // Primary skill for bosses. + Config.AttackSkill[2] = -1; // Backup/Immune skill for bosses. + Config.AttackSkill[3] = 0; // Primary skill for others. + Config.AttackSkill[4] = -1; // Backup/Immune skill for others. \ No newline at end of file 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/libs/config/Templates/chestlist.txt b/d2bs/kolbot/libs/config/Templates/chestlist.txt new file mode 100644 index 000000000..2f1c7b12e --- /dev/null +++ b/d2bs/kolbot/libs/config/Templates/chestlist.txt @@ -0,0 +1,28 @@ +ID Act1 +15 - Hole Level 2 +13 - Cave Level 2 +16 - Pit Level 2 +14 - Passage Level 2 +25 - Tower Level 5 +18 - Crypta +19 - Mausoleum + Act2 +55 - stony Tomb +65 - Ancient Tunnels +66-72 - Tal Tombs + Act3 +84 - SpiderCave +85 - SpiderCavern +77 - Marsh +90 - Smapy Grave +79 - lower Kurast +80 - Kurast Basar +92 - Sewers Level 1 +93 - Sewers Level 2 + Act5 +115 - Glacial Trail +116 - Drifter Cavern +119 - FrozenCellar +125 - Abbadon +126 - Archeon +127 - Infernal \ No newline at end of file diff --git a/d2bs/kolbot/libs/config/_CustomConfig.js b/d2bs/kolbot/libs/config/_CustomConfig.js new file mode 100644 index 000000000..86de0811e --- /dev/null +++ b/d2bs/kolbot/libs/config/_CustomConfig.js @@ -0,0 +1,9 @@ +var CustomConfig = { + /* Format: + "Config_Filename_Without_Extension": ["array", "of", "profiles"] + + Multiple entries are separated by commas + */ + + +}; \ No newline at end of file diff --git a/d2bot.log b/d2bs/kolbot/logs/deleteme similarity index 100% rename from d2bot.log rename to d2bs/kolbot/logs/deleteme diff --git a/profile.ini b/d2bs/kolbot/mules/deleteme similarity index 100% rename from profile.ini rename to d2bs/kolbot/mules/deleteme 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 c294c5537..d2a0a7e0b 100644 --- a/d2bs/kolbot/pickit/LLD.nip +++ b/d2bs/kolbot/pickit/LLD.nip @@ -24,12 +24,13 @@ //=== 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 [type] == amulet && [quality] == rare # [amazonskills]+[barbarianskills] == 1 && [maxhp] >= 40 && ([hpregen] >= 6 || [maxmana] >= 60) && [itemlevelreq] <= 30 -//[name] == amulet && [quality] == set # itemdamagetomana == 20 && itemlightradius == 3 // Angelic Wngs +//[name] == amulet && [quality] == set # [itemdamagetomana] == 20 && [itemlightradius] == 3 // Angelic Wngs //---vlld------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -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] == shortsiegebow || [name] == ashwoodbow || [name] == runebow) && [quality] == rare # [enhanceddamage] >= 140 && ([sockets] == 2 || [ias] == 20) && [itemlevelreq] <= 30 -[name] == cutlass && [quality] == rare # [enhanceddamage] >= 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] >= 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] >= 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] == 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]+[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 @@ -91,16 +93,25 @@ [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] == warscepter && [quality] <= superior && [flag] != ethereal# ([sockets] == 0 || [sockets] == 5) && [skilldefiance]+[skillsacrifice] >= 6 && [itemlevelreq] <= 9 -[name] == stagbow && [quality] == superior # ([sockets] == 0 || [sockets] == 5) && [enhanceddamage] == 15 && [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] == 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] == magic && [suffix] == 605 && [flag] != ethereal # [enhanceddamage] >= 30 && [itemlevelreq] <= 9 // sacrifice +([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 @@ -110,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 @@ -123,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 ======================================================================================================================================================================= @@ -133,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 @@ -143,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 ===================================================================================================================================================================== @@ -162,29 +183,29 @@ //[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 //---vlld------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -[name] == boneshield && [quality] == magic # [fbr] == 30 && [itemdamagetomana] >= 12 +[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 ======================================================================================================================================================================= @@ -209,8 +230,8 @@ //[name] == leathergloves && [quality] == set # [defense] == 3 // Death's Hand, perfect defense //[name] == wargauntlets && [quality] == set # [defense] == 118 // Immortal King's Forge, perfect defense -[name] == heavygloves && [quality] == unique && [flag] != ethereal # [enhanceddefense] == 20 // Bloodfist -[name] == lightgauntlets && [quality] == unique && [flag] != ethereal # [enhanceddefense] == 30 // Magefist +//[name] == heavygloves && [quality] == unique && [flag] != ethereal # [enhanceddefense] == 20 // Bloodfist +//[name] == lightgauntlets && [quality] == unique && [flag] != ethereal # [enhanceddefense] == 30 // Magefist //[name] == gauntlets && [quality] == unique && [flag] != ethereal # [enhanceddefense] == 20 // Frostburn [type] == gloves && [quality] == rare && [flag] != ethereal # [javelinandspearskilltab] == 2 && [ias] == 10 && [hpregen] >= 5 && [itemlevelreq] <= 30 @@ -221,12 +242,14 @@ //[name] == heavyboots && [quality] == set # [defense] == 6 // Sander's Riprap [name] == heavyboots && [quality] == set # [defense] >= 7 // Cow King's Hooves -[name] == meshboots && [quality] == set # [plusdefense] == 125 && [coldresist] == 25 && [lightresist] == 25 // Natalya's Soul, perfect +[name] == meshboots && [quality] == set # [defense] == 169 && [coldresist] == 25 && [lightresist] == 25 // Natalya's Soul, perfect [name] == boots && [quality] == unique && [flag] != ethereal # [enhanceddefense] == 20 // Hotspur -[name] == lightplatedboots && [quality] == unique && [flag] != ethereal # [enhanceddefense] == 60 // Goblin Toe +//[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 ====================================================================================================================================================================== //================================================================================================================================================================================= @@ -235,28 +258,29 @@ [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 # ([mindamage] >= 4 || [enhanceddamage] >= 20) && [maxdamage] >= 18 && [itemlevelreq] <= 30 -[name] == jewel && [quality] <= rare # ([enhanceddamage] >= 20 || [maxdamage] >= 18 || [mindamage] >= 8) && ([plusdefense] >= 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 +[name] == jewel && [quality] == rare # ([maxdamage] >= 9 || [mindamage] >= 4) && [itemreqpercent] < 0 && [itemlevelreq] <= 9 [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 ================================================================================================================================================================ @@ -264,14 +288,14 @@ //[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 || [plusdefense] == 20 || [fireresist] >= 9 || [lightresist] >= 9 || [coldresist] >= 9 || [fireresist] >= 5 && [coldresist] >= 5) && [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 //---vlld------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -[name] == smallcharm && [quality] == magic # [maxhp] >= 15 && ([poisonmaxdam] == 52 && [maxmana] >= 5 || [tohit] >= 10 || [plusdefense] >= 8) && [itemlevelreq] <= 18 +[name] == smallcharm && [quality] == magic # [maxhp] >= 15 && ([poisonmaxdam] == 52 && [maxmana] >= 5 || [tohit] >= 10 || [defense] >= 8) && [itemlevelreq] <= 18 [name] == smallcharm && [quality] == magic # [poisonmaxdam] == 91 // 62 pdsc level 18 //================================================================================================================================================================================= @@ -285,14 +309,14 @@ [name] == largecharm && [quality] == magic # ([frw] == 7 || [fhr] == 17) && [maxmana] == 33 //[name] == largecharm && [quality] == magic # [maxhp] == 15 && [itemlevelreq] <= 9 [name] == largecharm && [quality] == magic # ([strength] == 3 || [dexterity] == 3) && [tohit] >= 12 && [itemlevelreq] <= 9 -[name] == largecharm && [quality] == magic # [maxhp] >= 15 && ([tohit] >= 10 || [maxmana] >= 5 || [plusdefense] >= 3) && [itemlevelreq] <= 9 +[name] == largecharm && [quality] == magic # [maxhp] >= 15 && ([tohit] >= 10 || [maxmana] >= 5 || [defense] >= 3) && [itemlevelreq] <= 9 [name] == largecharm && [quality] == magic # [frw] == 5 && [maxmana] == 18 //================================================================================================================================================================================= //=== 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 @@ -307,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 @@ -342,12 +372,16 @@ //---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]+[skillbonearmor] >= 6 && [itemlevelreq] <= 9 // spawns on ilvl < 25 + //---PALADIN---------------------------------------------------------------------------------------------------------------------------------------------------------------------- ([name] == akarantarge || [name] == akaranrondache) && [quality] <= superior # [enhanceddamage] == 65 && [tohit] == 121 && ([sockets] == 0 || [sockets] == 4) @@ -355,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-------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -368,8 +401,9 @@ //---vlld------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -[type] == orb && [quality] <= rare # [fcr] == 10 && [skilliceblast] == 3 && [coldskilltab] == 1 -[type] == orb && [quality] <= rare # [fcr] == 10 && [skillfireball] == 3 && [fireskilltab] == 1 +[type] == orb && [class] == normal && [quality] <= rare # [fcr] == 10 && [skilliceblast] == 3 && [coldskilltab] == 1 && [itemlevelreq] <= 18 +[type] == orb && [class] == normal && [quality] <= rare # [fcr] == 10 && [skillfireball] == 3 && [fireskilltab] == 1 && [itemlevelreq] <= 18 +[type] == orb && [class] == normal && [quality] <= rare # [fcr] == 10 && [skilliceblast] == 3 && [skillwarmth] > 0 && [skillfrozenarmor] > 0 && [itemlevelreq] <= 9 //================================================================================================================================================================================= //=== IMBUEABLES ================================================================================================================================================================== diff --git a/d2bs/kolbot/pickit/classic.nip b/d2bs/kolbot/pickit/classic.nip index 32e8d8d94..f93b955bd 100644 --- a/d2bs/kolbot/pickit/classic.nip +++ b/d2bs/kolbot/pickit/classic.nip @@ -6,11 +6,11 @@ [type] == amulet && [quality] == rare # [sorceressskills]+[necromancerskills]+[paladinskills] >= 1 && [maxhp] >= 35 && ([maxmana] >= 50 || [strength] >= 15 || [dexterity] >= 10) [type] == amulet && [quality] == rare # [sorceressskills]+[necromancerskills]+[paladinskills] >= 1 && [maxmana] >= 50 && ([maxhp] >= 35 || [strength] >= 15 || [dexterity] >= 10) -[type] == amulet && [quality] == rare # [mamzonskills]+[sorceressskills]+[necromancerskills]+[paladinskills]+[barbarianskills] >= 1 && [fireresist]+[lightresist]+[coldresist]+[poisonresist] >= 64 && ([maxhp]+[maxmana] >= 50 || [strength]+[dexterity] >= 15 || [fcr] == 10) -[type] == amulet && [quality] == rare # [mamzonskills]+[sorceressskills]+[necromancerskills]+[paladinskills]+[barbarianskills] == 2 && ([fireresist]+[lightresist]+[coldresist]+[poisonresist] >= 64 || [fcr] == 10 && [maxhp]+[maxmana] >= 50) +[type] == amulet && [quality] == rare # [amazonskills]+[sorceressskills]+[necromancerskills]+[paladinskills]+[barbarianskills] >= 1 && [fireresist]+[lightresist]+[coldresist]+[poisonresist] >= 64 && ([maxhp]+[maxmana] >= 50 || [strength]+[dexterity] >= 15 || [fcr] == 10) +[type] == amulet && [quality] == rare # [amazonskills]+[sorceressskills]+[necromancerskills]+[paladinskills]+[barbarianskills] == 2 && ([fireresist]+[lightresist]+[coldresist]+[poisonresist] >= 64 || [fcr] == 10 && [maxhp]+[maxmana] >= 50) [type] == amulet && [quality] == rare # [paladinskills] >= 1 && [fireresist]+[lightresist]+[coldresist]+[poisonresist] >= 64 -[type] == amulet && [quality] <= rare # [barbarianskills] == 2 || [sorceressskills] == 2 +//[type] == amulet && [quality] <= rare # [barbarianskills] == 2 || [sorceressskills] == 2 //------ rings ------ @@ -29,10 +29,9 @@ //------ armor ------ -[type] == armor && [quality] == rare # [maxhp] >= 50 && ([coldresist] >= 20) + ([fireresist] >= 20) + ([lightresist] >= 20) >= 2 [type] == armor && [quality] == rare # [fhr] == 24 && [maxhp] >= 30 && ([coldresist] >= 20) + ([fireresist] >= 20) + ([lightresist] >= 20) >= 2 -[name] == ornateplate && [quality] == rare # [enhanceddefense] >= 90 && ([itemreqpercent] < 0 || [maxhp] > 30 || [strength] >= 10) -[name] == mageplate && [quality] == rare # [enhanceddefense] >= 70 && [maxhp] >= 30 && ([coldresist] >= 20) + ([fireresist] >= 20) + ([lightresist] >= 20) >= 2 +[name] == ornateplate && [quality] == rare # ([enhanceddefense] >= 90) + ([itemreqpercent] < 0) + ([maxhp] >= 30) + ([strength] >= 10) >= 3 +[name] == mageplate && [quality] == rare # [enhanceddefense] >= 60 && [maxhp] >= 30 && ([coldresist] >= 20) + ([fireresist] >= 20) + ([lightresist] >= 20) >= 2 [type] == armor && [quality] == rare # [fireresist]+[coldresist]+[lightresist] >= 50 && [itemlightradius] == 2 // BANANA //------ boots ------ @@ -49,7 +48,7 @@ [type] == helm && [quality] == rare # [fhr] == 10 && [maxhp] >= 30 && ([coldresist] >= 20) + ([fireresist] >= 20) + ([lightresist] >= 20) >= 2 -[name] == grimhelm && [quality] == rare # [enhanceddefense] >= 70 && ([coldresist] >= 20) + ([fireresist] >= 20) + ([lightresist] >= 20) >= 2 +[name] == grimhelm && [quality] == rare # [enhanceddefense] >= 60 && ([coldresist] >= 20) + ([fireresist] >= 20) + ([lightresist] >= 20) >= 2 [name] == grimhelm && [quality] == rare # [enhanceddefense] >= 90 && [maxhp] >= 30 && ([itemtohitpercent] == 5 || [tohit] >= 30) ([name] == bonehelm || [name] == grimhelm) && [quality] == rare # [itemlightradius] == 2 && ([coldresist] >= 20) + ([fireresist] >= 20) + ([lightresist] >= 20) >= 2 // BANANA @@ -63,8 +62,8 @@ [type] == wand && [quality] == rare # [fcr] == 20 && ([coldresist] >= 30) + ([fireresist] >= 30) + ([lightresist] >= 30) >= 2 && [maxmana] >= 30 //[type] == wand && [quality] <= rare # [fcr] == 20 && [necromancerskills] == 2 && [skillbonespear] >= 3 //[type] == wand && [quality] <= rare # [fcr] == 20 && [necromancerskills] == 2 && [skillcorpseexplosion] >= 3 -[type] == scepter && [quality] <= rare # [paladinskills] == 2 && ([fcr] >= 10 && [skillblessedhammer]+[skillconcentration] >= 5 || [skillholyshield] >= 3) -//([type] == mace || [type] == club || [type] == sword) && [quality] == rare # [barbarianskills] == 2 && ([fireresist] >= 25 || [coldresist] >= 25 || [lightresist] >= 25) +[type] == scepter && [quality] <= rare # [paladinskills] == 2 && ([fcr] >= 10 && ([skillblessedhammer] == 3 || [skillconcentration] == 3) || [skillblessedhammer]+[skillconcentration] >= 6 || [skillholyshield] >= 3) +([type] == mace || [type] == club || [type] == sword) && [quality] == rare # [barbarianskills] == 2 && ([fireresist] >= 25 || [coldresist] >= 25 || [lightresist] >= 25) //[type] == staff && [quality] <= rare # [sorceressskills]+[skillenchant] == 5 //------ shields ------ @@ -96,6 +95,7 @@ // ===================================================================================================================== //------ amulets ------ +//[name] == amulet && [quality] == unique //------ rings ------ @@ -116,8 +116,8 @@ //------ boots ------ -[name] == boots && [quality] == unique -[name] == greaves && [quality] == unique # # [maxquantity] == 1 +//[name] == boots && [quality] == unique +//[name] == greaves && [quality] == unique # # [maxquantity] == 1 //[name] == lightplatedboots && [quality] == unique # [enhanceddefense] == 60 //------ gloves ------ @@ -144,16 +144,19 @@ [name] == gothicshield && [quality] == unique # [fireresist] >= 50 //[name] == gothicshield && [quality] == unique +//------- bows ------- +//[name] == longbow && [quality] == unique + // ===================================================================================================================== // === SET ============================================================================================================= // ===================================================================================================================== //------ Angelic Raiment ------ -//[name] == ringmail && [quality] == set # [enhanceddefense] == 40 -//[name] == sabre && [quality] == set # [tohit] == 75 -//[name] == ring && [quality] == set # [maxhp] == 20 -//[name] == amulet && [quality] == set # [itemdamagetomana] == 20 +//[name] == ringmail && [quality] == set # [enhanceddefense] == 40 # [maxquantity] == 1 +//[name] == sabre && [quality] == set # [tohit] == 75 # [maxquantity] == 1 +//[name] == ring && [quality] == set # [maxhp] == 20 # [maxquantity] == 2 +//[name] == amulet && [quality] == set # [itemdamagetomana] == 20 # [maxquantity] == 1 //------ Arcanna's Tricks ------ @@ -184,6 +187,8 @@ //------ Cleglaw's Brace ------ //------ Death's Disguise ------ +//[name] == leathergloves && [quality] == set +//[name] == sash && [quality] == set //------ Hsarus' Defense ------ @@ -213,8 +218,8 @@ [name] == greaterhealingpotion [name] == supermanapotion [name] == superhealingpotion -//[Name] == RejuvenationPotion -//[Name] == FullRejuvenationPotion +[Name] == RejuvenationPotion +[Name] == FullRejuvenationPotion //[name] == ringmail && [quality] == set # # [maxquantity] == 1 //[name] == Sabre && [quality] == set # # [maxquantity] == 1 @@ -237,21 +242,24 @@ [Type] == gold # [Gold] >= 10000 -[type] == scepter && [quality] <= rare # [paladinskills] == 2 && [fcr] >= 10 && ([skillblessedhammer] === 3 || [skillconcentration] >= 3) - //ladder reset -[type] == ring && [quality] == rare # [fcr] == 10 && [maxmana] >= 40 +//[type] == ring && [quality] == rare # [fcr] == 10 && [maxmana] >= 40 -[type] == armor && [quality] >= magic && [class] == exceptional # [strength] > 100 -[type] == helm && [quality] >= magic && [class] == exceptional # [strength] > 100 -[type] == weapon && [quality] >= magic && [class] == exceptional # [strength] > 100 +//[type] == armor && [quality] >= magic # [strength] > 100 +//[type] == helm && [quality] >= magic # [strength] > 100 +//[type] == shield && [quality] >= magic # [strength] > 100 //[type] == ring && [quality] <= rare # [maxmana] >= 35 +//[type] == wand && [quality] <= rare # [maxmana] >= 35 && [fcr] == 20 # [maxquantity] == 1 //[type] == amulet && [quality] <= rare # [maxmana] >= 60 +//[name] == mask && [quality] <= rare # [energy] == 9 # [maxquantity] == 1 + +//[name] == mask && [quality] == unique # # [maxquantity] == 1 +//[name] == platedbelt && [quality] == set # # [maxquantity] == 1 +//[name] == greaves && [quality] == set # # [maxquantity] == 1 //[name] == flawlessskull //[name] == flawlessdiamond -[type] == amulet && [quality] == rare # [sorceressskills]+[paladinskills] >= 1 && [fireresist]+[lightresist]+[coldresist]+[poisonresist] >= 64 -[type] == belt && [name] >= platedbelt && [quality] == rare # [maxhp] >= 30 && ([coldresist] >= 20) + ([fireresist] >= 20) + ([lightresist] >= 20) >= 2 -[type] == armor && [quality] == rare # [maxhp] >= 30 && ([coldresist] >= 20) + ([fireresist] >= 20) + ([lightresist] >= 20) >= 2 + +[type] == belt && [name] >= platedbelt && [quality] == rare # [maxhp] >= 30 && ([coldresist] >= 20) + ([fireresist] >= 20) + ([lightresist] >= 20) >= 2 \ No newline at end of file diff --git a/d2bs/kolbot/pickit/follower.nip b/d2bs/kolbot/pickit/follower.nip index 46d876fd0..0b77c30ca 100644 --- a/d2bs/kolbot/pickit/follower.nip +++ b/d2bs/kolbot/pickit/follower.nip @@ -1,8 +1,63 @@ -// just a simple gold/pot pickit - [name] == gold [type] == healingpotion [type] == manapotion [type] == rejuvpotion -[quality] >= magic # [strength] > 100 \ No newline at end of file +[quality] >= magic # [strength] > 100 + +[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/gold.nip b/d2bs/kolbot/pickit/gold.nip index bac329b6a..c3011ae06 100644 --- a/d2bs/kolbot/pickit/gold.nip +++ b/d2bs/kolbot/pickit/gold.nip @@ -1 +1 @@ -[name] == gold # [gold] >= 7500 \ No newline at end of file +[name] == gold # [gold] >= 500 \ No newline at end of file diff --git a/d2bs/kolbot/pickit/keyorg.nip b/d2bs/kolbot/pickit/keyorg.nip new file mode 100644 index 000000000..2aa6c75d7 --- /dev/null +++ b/d2bs/kolbot/pickit/keyorg.nip @@ -0,0 +1,5 @@ +[name] == diablo'shorn || [name] == mephisto'sbrain || [name] == baal'seye +[name] == keyofhate # # [maxquantity] == 5 +[name] == keyofterror # # [maxquantity] == 5 +[name] == keyofdestruction # # [maxquantity] == 5 +[name] == largecharm && [quality] == unique \ No newline at end of file diff --git a/d2bs/kolbot/pickit/kolton.nip b/d2bs/kolbot/pickit/kolton.nip index 73a85dbc3..cabc205d1 100644 --- a/d2bs/kolbot/pickit/kolton.nip +++ b/d2bs/kolbot/pickit/kolton.nip @@ -69,6 +69,7 @@ [name] == sacredarmor && [quality] == unique && [flag] == ethereal # [enhanceddefense] >= 220 // templar's might [name] == sacredarmor && [quality] == unique # [strength] >= 20 // tyrael's might [name] == serpentskinarmor && [quality] == unique # [fireresist] == 35 && [magicdamagereduction] == 13 // skin of the vipermagi +[name] == wyrmhide && [quality] == unique # [defense] == 1034 // skin of the vipermagi x1 [name] == demonhidearmor && [quality] == unique && [flag] == ethereal # [enhanceddefense] == 190 // skin of the flayed one eth [name] == linkedmail && [quality] == unique && [flag] == ethereal # [enhanceddefense] == 160 // spirit forge eth [name] == cuirass && [quality] == unique && [flag] == ethereal # [enhanceddefense] == 200 // duriel's shell eth @@ -97,16 +98,21 @@ //[name] == monarch && [quality] <= superior # [sockets] == 4 # [maxquantity] == 1 // ==unique== -[name] == spikedshield && [quality] == unique # [enhanceddefense] == 60 // swordback hold -[name] == barbedshield && [quality] == unique && [flag] == identified # [defense] == 134 || [defense] == 197 // swordback hold x1 -//[name] == monarch && [quality] == unique # [defense] == 148 // stormshield +//[name] == spikedshield && [quality] == unique # [enhanceddefense] == 60 // swordback hold +[name] == spikedshield && [quality] == unique && [flag] == ethereal # [enhanceddefense] == 60 // swordback hold eth +[name] == monarch && [quality] == unique # [defense] == 148 // stormshield //[name] == trollnest && [quality] == unique && [flag] == ethereal # [sockets] == 3 // head hunter's glory //[name] == defender && [quality] == unique # [enhanceddefense] == 150 // visceratuant [name] == roundshield && [quality] == unique # [enhanceddefense] == 220 // moser -[name] == luna && [quality] == unique && [flag] == identified # [defense] == 393 || [defense] == 588 // moser x1 [name] == barbedshield && [quality] == unique && [flag] == ethereal # [enhanceddefense] == 120 // lanceguard eth //[name] == grimshield && [quality] == unique # [enhanceddefense] == 130 && [itemmanaafterkill] == 5 // lidless wall +// upgrades +[name] == barbedshield && [quality] == unique && [flag] == identified // # [defense] == 134 || [defense] == 197 // swordback hold x1 (noneth/eth) +[name] == bladebarrier && [quality] == unique && [flag] == identified # [defense] == 270 || [defense] == 401 // swordback hold x2 (noneth/eth) +[name] == bladebarrier && [quality] == unique && [flag] == identified # [defense] == 536 // lanceguard eth x1 +[name] == luna && [quality] == unique && [flag] == identified # [defense] == 393 || [defense] == 588 // moser x1 (noneth/eth) + // ==rare== // ==magic== @@ -122,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 @@ -196,8 +202,9 @@ // ==white== // ==unique== -[name] == lightplatedboots && [quality] == unique && [flag] != ethereal # [enhanceddefense] == 60 // goblin toe -[name] == battleboots && [quality] == unique # [defense] == 90 // goblin toe x1 +//[name] == lightplatedboots && [quality] == unique && [flag] != ethereal # [enhanceddefense] == 60 // goblin toe +//[name] == battleboots && [quality] == unique && [flag] == identified // # [defense] == 90 // goblin toe x1 +//[name] == mirroredboots && [quality] == unique && [flag] == identified # [defense] == 123 // goblin toe x2 [name] == warboots && [quality] == unique && [flag] != ethereal # [enhanceddefense] == 200 // gore rider [name] == myrmidongreaves && [quality] == unique && [flag] == identified # [defense] == 213 // gore rider x1 [name] == scarabshellboots && [quality] == unique && [flag] == ethereal # [strength]+[vitality] == 30 // sandstorm trek @@ -274,7 +281,7 @@ //[name] == hydrabow && [quality] == unique # [manaleech] == 8 //windforce // ==rare== -//[type] == bow && [quality] == rare # [enhanceddamage] >= 400 && ([ias] == 20 || [sockets] == 2) +[type] == bow && [quality] == rare # [enhanceddamage] >= 400 && ([ias] == 20 || [sockets] == 2) // ==magic== @@ -325,7 +332,7 @@ // ==white== //[name] >= thresher && [name] <= greatpoleaxe && [quality] == normal && [flag] == ethereal # [sockets] == 0 # [maxquantity] == 1 // for socketing -[type] == polearm && [quality] <= superior && [flag] == ethereal && [class] == elite # [sockets] == 4 && [enhanceddamage] == 15 +[type] == polearm && [quality] <= superior && [flag] == ethereal && [class] == elite # [sockets] == 4 [name] == colossusvoulge && [quality] <= superior && [flag] == ethereal # ([sockets] == 0 || [sockets] == 4) && [enhanceddamage] == 15 // ==unique== @@ -489,7 +496,7 @@ ([name] == claws || [name] == greaterclaws || [name] == feralclaws) && [quality] == rare # [itemtohitperlevel] > 0 && [ias] >= 40 && [sockets] == 2 ([name] == bladetalons || [name] == greatertalons || [name] == runictalons) && [quality] == rare # [enhanceddamage] >= 225 && [itemtohitperlevel] > 0 && [ias] >= 30 ([name] == claws || [name] == greaterclaws || [name] == feralclaws) && [quality] == rare # [enhanceddamage] >= 225 && [itemtohitperlevel] > 0 && [ias] >= 40 -[type] == handtohand && [quality] == rare && [flag] == ethereal # [enhanceddamage] >= 225 && [itemtohitperlevel] > 0 || [enhanceddamage] >= 400 +([type] == handtohand || [type] == assassinclaw) && [quality] == rare && [flag] == ethereal # [enhanceddamage] >= 225 && [itemtohitperlevel] > 0 || [enhanceddamage] >= 400 // ==magic== ([name] == greatertalons || [name] == runictalons) && [quality] == magic # [assassinskills]+[skilllightningsentry] == 5 || [trapsskilltab]+[skilllightningsentry] == 6 @@ -526,6 +533,7 @@ // ==unique== [name] == slayerguard && [quality] == unique # [enhanceddefense] >= 200 // arreat's face +[name] == guardiancrown && [quality] == unique # [defense] == 504 || [defense] == 756 // arreat's face x1 //[name] == slayerguard && [quality] == unique && [flag] == ethereal // arreat's face [name] == furyvisor && [quality] == unique && [flag] != ethereal # [warcriesskilltab] == 3 && [skillwerewolf]+[skilllycanthropy]+[skillferalrage] == 18 && [strength]+[dexterity]+[vitality] >= 45 // wolfhowl @@ -560,7 +568,7 @@ // ==unique== [name] == totemicmask && [quality] == unique # [enhanceddefense] == 200 // jalal's mane -[name] == bloodspirit && [quality] == unique && [flag] == identified # [defense] == 477 // jalal's mane x1 +[name] == bloodspirit && [quality] == unique && [flag] == identified # [defense] == 477 || [defense] == 714 // jalal's mane x1 [name] == bloodspirit && [quality] == unique # [enhanceddefense] == 140 && [itemtohitpercent] == 120 && [shapeshiftingskilltab] == 4 && [skillferalrage] == 2 && [lifeleech] == 10 // cerebus' bite // ==rare== @@ -576,8 +584,10 @@ // ==white== [type] == auricshields && [quality] == normal && [class] == elite && [flag] == ethereal # ([enhanceddamage] == 65 && [tohit] == 121 || [fireresist] >= 45) && [sockets] == 0 // exile -[type] == auricshields && [quality] == normal && [class] == elite # ([enhanceddamage] == 65 && [tohit] == 121 || [fireresist] >= 45) && [sockets] == 0 // for socketing -[type] == auricshields && [quality] <= superior && [class] == elite # ([enhanceddamage] == 65 && [tohit] == 121 || [fireresist] >= 45) && ([sockets] == 3 || [sockets] == 4) +//[type] == auricshields && [quality] == normal && [class] == elite && [flag] != ethereal # ([enhanceddamage] == 65 && [tohit] == 121 || [fireresist] >= 45) && [sockets] == 0 // for socketing +//[type] == auricshields && [quality] <= superior && [class] == elite && [flag] != ethereal # ([enhanceddamage] == 65 && [tohit] == 121 || [fireresist] >= 45) && [sockets] == 3 +[type] == auricshields && [quality] <= superior && [class] == elite && [flag] != ethereal # ([enhanceddamage] == 65 && [tohit] == 121 || [fireresist] >= 45) && [sockets] == 4 +[type] == auricshields && [quality] == superior && [class] == elite && [flag] != ethereal # [enhanceddefense] == 15 && ([itemmaxdurabilitypercent] == 0 || [itemmaxdurabilitypercent] == 15) && ([enhanceddamage] == 65 && [tohit] == 121 || [fireresist] >= 45) && ([sockets] == 0 || [sockets] == 3 || [sockets] == 4) // ==unique== [name] == sacredrondache && [quality] == unique # [paladinskills] == 2 && [enhanceddefense] >= 200 && [enhanceddamage] >= 70 && [itemtohitpercent] >= 70 // alma negra @@ -627,9 +637,9 @@ [name] >= istrune && [name] <= zodrune -//[name] == keyofhate # # [maxquantity] == 3 -//[name] == keyofterror # # [maxquantity] == 3 -//[name] == keyofdestruction # # [maxquantity] == 3 +[name] == keyofhate # # [maxquantity] == 3 +[name] == keyofterror # # [maxquantity] == 3 +[name] == keyofdestruction # # [maxquantity] == 3 [name] == diablo'shorn [name] == mephisto'sbrain @@ -646,7 +656,7 @@ [Name] == jewel && [Quality] == rare # [strength] >= 9 && [dexterity] >= 9 [Name] == jewel && [Quality] == rare # [fhr] == 7 && ([strength] >= 8 || [dexterity] >= 8 || [itemreqpercent] == -15) && ([maxmana] == 15 || [fireresist] >= 10 && [coldresist] >= 10 || [fireresist] >= 30 || [coldresist] >= 30 || [lightresist] >= 30) [Name] == jewel && [Quality] == rare # [fhr] == 7 && [energy] == 9 && [maxmana] == 15 -[Name] == jewel && [Quality] == rare # [enhanceddamage] >= 25 && ([strength] >= 8 || [dexterity] >= 8) && ([tohit] >= 40 || [itemreqpercent] == -15 || [plusdefense] >= 30) +[Name] == jewel && [Quality] == rare # [enhanceddamage] >= 25 && ([strength] >= 8 || [dexterity] >= 8) && ([tohit] >= 40 || [itemreqpercent] == -15 || [defense] >= 30) // ==unique== [Name] == jewel && [quality] == unique # [passivecoldpierce]+[passivecoldmastery] >= 10 || [passivepoispierce]+[passivepoismastery] >= 10 || [passiveltngpierce]+[passiveltngmastery] >= 10 || [passivefirepierce]+[passivefiremastery] >= 10 @@ -665,7 +675,7 @@ [name] == smallcharm && [quality] == magic # [itemmagicbonus] == 7 && ([fireresist] >= 11 || [coldresist] >= 11 || [lightresist] >= 11 || [fireresist]+[lightresist]+[coldresist] == 15 || [maxmana] >= 17) [name] == smallcharm && [quality] == magic # [poisonmaxdam] >= 205 && ([maxhp] >= 20 || [frw] == 3) [name] == smallcharm && [quality] == magic # [poisonmaxdam] == 291 || [poisonmaxdam] == 338 || [poisonmaxdam] == 351 || [poisonmaxdam] == 385 // 313, 330, 377, 451 -[name] == smallcharm && [quality] == magic # [itemgoldbonus] == 10 && ([poisonmaxdam] == 299 || [maxdamage] == 3 || [maxmana] == 17 || [fireresist] == 11 || [fireresist] == 5 && [lightresist] == 5) +[name] == smallcharm && [quality] == magic # [itemgoldbonus] == 10 && ([tohit] >= 30 || [poisonmaxdam] == 299 || [maxdamage] == 3 || [maxmana] == 17 || [fireresist] == 11 || [fireresist] == 5 && [lightresist] == 5) //[name] == smallcharm && [quality] == magic # [itemgoldbonus] == 10 [name] == smallcharm && [quality] == unique @@ -687,11 +697,11 @@ //[name] == grandcharm && [quality] == magic # [lightningskilltab] == 1 //[name] == grandcharm && [quality] == magic # [javelinandspearskilltab] == 1 //[name] == grandcharm && [quality] == magic # [trapsskilltab] == 1 -[name] == grandcharm && [quality] == magic # [itemgoldbonus] == 40 && ([warcriesskilltab] == 1 || [maxdamage] == 10 || [maxmana] == 59 || [fireresist] == 15 && [coldresist] == 15) +[name] == grandcharm && [quality] == magic # [itemgoldbonus] == 40 && ([tohit] >= 130 || [warcriesskilltab] == 1 || [maxdamage] == 10 || [maxmana] == 59 || [fireresist] == 15 && [coldresist] == 15) [name] == grandcharm && [quality] == magic # [maxmana] == 59 && ([maxhp] >= 30 || [fhr] == 12) //[name] == grandcharm && [quality] == magic # [itemgoldbonus] == 40 -[name] == grandcharm && [quality] == unique # [itemmagicbonus] >= 35 || [itemgoldbonus] >= 150 +[name] == grandcharm && [quality] == unique # [itemmagicbonus] >= 35 // || [itemgoldbonus] >= 150 // --set items-- @@ -735,7 +745,7 @@ // Shields // Gloves -[type] == gloves && [quality] == crafted # [itemknockback] >= 1 && [ias] >= 20 && [strength]+[dexterity] >= 15 +[type] == gloves && [quality] == crafted # [ias] >= 20 && [strength]+[dexterity] >= 15 // Boots [type] == boots && [quality] == crafted # [itemmaxmanapercent] >= 4 && [maxmana] >= 40 @@ -743,7 +753,6 @@ // Belts [type] == belt && [class] >= exceptional && [quality] == crafted # [maxhp] >= 50 && [strength] >= 15 [type] == belt && [class] >= exceptional && [quality] == crafted # [fhr] == 24 && [fcr] == 10 -[name] == lightbelt && [quality] == crafted # [fhr] == 24 && [fcr] == 10 && [itemlevelreq] <= 30 // Rings [type] == ring && [quality] == crafted # [strength]+[dexterity] >= 25 && [maxhp] >= 30 @@ -753,14 +762,14 @@ [type] == amulet && [quality] == crafted # [assassinskills] == 2 && [fcr] >= 15 [type] == amulet && [quality] == crafted # [druidskills] == 2 && [fcr] >= 18 -[type] == amulet && [quality] == crafted # [itemaddclassskills] >= 2 && ([fcr] >= 20 || [strength]+[dexterity] >= 25 || [maxhp]+[maxmana] >= 50) +[type] == amulet && [quality] == crafted # [itemaddclassskills] >= 2 && [fcr] >= 10 && ([strength]+[dexterity] >= 25 || [maxhp]+[maxmana] >= 50) [name] == jewel && [quality] == rare # [fireresist] >= 35 [type] == boots && [quality] == crafted # [maxmana] >= 40 && [itemmaxmanapercent] >= 4 // unid packs -([name] == assaulthelmet || [name] == avengerguard || [name] == savagehelmet || [name] == slayerguard || [name] == conquerorcrown || [name] == guardiancrown) && [quality] == rare && [prefix] == 1286 -([name] == antlers || [name] == hunter'sguise || [name] == earthspirit) && [quality] == rare && [prefix] == 1286 +([name] == assaulthelmet || [name] == avengerguard || [name] == savagehelmet || [name] == slayerguard || [name] == conquerorcrown || [name] == guardiancrown) && [quality] == rare && [color] == white +([name] == antlers || [name] == hunter'sguise || [name] == earthspirit) && [quality] == rare && [color] == white [name] == tokenofabsolution @@ -776,8 +785,8 @@ //[name] == demonhead && [quality] == unique //[name] == tulwar && [quality] == unique # # [maxquantity] == 1 //[name] == trollnest && [quality] <= superior && [flag] != ethereal # [sockets] == 2 # [maxquantity] == 1 -[name] == demonhideboots && [quality] == unique # [itemgoldbonus] == 70 -[type] == boots && [quality] == rare # [itemgoldbonus] == 80 && [fireresist] >= 30 +//[name] == demonhideboots && [quality] == unique # [itemgoldbonus] == 70 +//[type] == boots && [quality] == rare # [itemgoldbonus] == 80 && [fireresist] >= 30 //[name] == phaseblade && [quality] <= superior # [sockets] == 5 //[name] == heavybelt && [quality] == unique && [flag] != ethereal # [itemgoldbonus] == 80 // goldwrap //[type] == belt && [quality] == rare && [flag] != ethereal # [itemgoldbonus] == 80 @@ -798,12 +807,4 @@ //[name] == eldritchorb && [quality] == unique # [sorceressskills] == 3 && [passiveltngmastery] == 20 //[name] == crystalsword && [quality] <= superior && [flag] == ethereal # [sockets] == 4 //[name] == balancedknife && [quality] == magic # [warcriesskilltab] == 3 -[name] == vambraces && [quality] == unique # [itemmagicbonus] > 0 - -// Tr0uble@jsp -([name] == gnarledstaff || [name] == battlestaff || [name] == gothicstaff || [name] == cedarstaff || [name] == shillelagh || [name] == elderstaff) && [quality] <= superior # ([sockets] == 0 || [sockets] == 4) && ([skillcoldmastery] > 0 && ([skillblizzard] > 0 && [skillglacialspike] > 0 || [skillfrozenorb] > 0 && [skillenchant]+[skillthunderstorm] > 0) || [skillicebolt] > 0 && [skilliceblast] > 0 && [skillwarmth] > 0) -([name] == warstaff || [name] == runestaff || [name] == archonstaff) && [quality] <= superior # [sockets] == 4 && ([skillcoldmastery] > 0 && ([skillblizzard] > 0 && [skillglacialspike] > 0 || [skillfrozenorb] > 0 && [skillenchant]+[skillthunderstorm] > 0) || [skillicebolt] > 0 && [skilliceblast] > 0 && [skillwarmth] > 0) - -//([name] == crystalsword || [name] == flail || [name] == waraxe || [name] == militarypick) && [quality] <= superior # [sockets] == 5 # [maxquantity] == 1 - -[name] == grandcharm && [quality] == magic # [coldskilltab] == 1 \ No newline at end of file +//[name] == vambraces && [quality] == unique # [itemmagicbonus] > 0 \ No newline at end of file diff --git a/d2bs/kolbot/pickit/pots.nip b/d2bs/kolbot/pickit/pots.nip index 85bab99e4..6b96443eb 100644 --- a/d2bs/kolbot/pickit/pots.nip +++ b/d2bs/kolbot/pickit/pots.nip @@ -4,4 +4,4 @@ [name] == supermanapotion [name] == rejuvenationpotion [name] == fullrejuvenationpotion -[name] == gold # [gold] >= 2000 \ No newline at end of file +[name] == gold # [gold] >= 500 \ No newline at end of file diff --git a/d2bs/kolbot/pickit/pots/pots.nip b/d2bs/kolbot/pickit/pots/pots.nip deleted file mode 100644 index 85bab99e4..000000000 --- a/d2bs/kolbot/pickit/pots/pots.nip +++ /dev/null @@ -1,7 +0,0 @@ -[name] == greaterhealingpotion -[name] == superhealingpotion -[name] == greatermanapotion -[name] == supermanapotion -[name] == rejuvenationpotion -[name] == fullrejuvenationpotion -[name] == gold # [gold] >= 2000 \ No newline at end of file diff --git a/d2bs/kolbot/pickit/shopbot.nip b/d2bs/kolbot/pickit/shopbot.nip index a612914c9..c79ee9097 100644 --- a/d2bs/kolbot/pickit/shopbot.nip +++ b/d2bs/kolbot/pickit/shopbot.nip @@ -1,12 +1,143 @@ -// Use only this pickit when running Scripts.ShopBot for maximum speed -// Comment out the lines for items you don't want to scan - -[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 \ No newline at end of file +// 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. + +// =============== +// ===== 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 + +// Enchant staff (Ormus) +//[type] == staff # [sorceressskills] == 2 && [skillenchant] == 3 // Any color (green is plain +2) +//[type] == staff && [color] == darkred # [sorceressskills] == 2 && [skillenchant] == 3 +//[type] == staff && [color] == darkblue # [sorceressskills] == 2 && [skillenchant] == 3 +//[type] == staff && [color] == darkyellow # [sorceressskills] == 2 && [skillenchant] == 3 +//[type] == staff && [color] == darkgold # [sorceressskills] == 2 && [skillenchant] == 3 +//[type] == staff && [color] == crystalred # [sorceressskills] == 2 && [skillenchant] == 3 + +//[name] == crystalsword # [barbarianskills] == 2 + +// ==================== +// ====== 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/pickit/test.nip b/d2bs/kolbot/pickit/test.nip index a52254e8c..e69de29bb 100644 --- a/d2bs/kolbot/pickit/test.nip +++ b/d2bs/kolbot/pickit/test.nip @@ -1 +0,0 @@ -[quality] >= magic # [strength] > 100 \ No newline at end of file diff --git a/d2bs/kolbot/sdk/Shrines.txt b/d2bs/kolbot/sdk/Shrines.txt new file mode 100644 index 000000000..d56897a44 --- /dev/null +++ b/d2bs/kolbot/sdk/Shrines.txt @@ -0,0 +1,23 @@ +0 null +1 refilling +2 health +3 mana +4 health exchange +5 mana exchange +6 armor +7 combat +8 resist fire +9 resist cold +10 resist lightning +11 resist poison +12 skill +13 mana recharge +14 stamina +15 experience +16 enirhs +17 portal +18 gem +19 fire +20 monster +21 exploding +22 poison \ No newline at end of file diff --git a/d2bs/kolbot/sdk/SuperUniques.txt b/d2bs/kolbot/sdk/SuperUniques.txt new file mode 100644 index 000000000..66b755521 --- /dev/null +++ b/d2bs/kolbot/sdk/SuperUniques.txt @@ -0,0 +1,68 @@ +Name hcIdx +Bishibosh 0 +Bonebreak 1 +Coldcrow 2 +Rakanishu 3 +Treehead WoodFist 4 +Griswold 5 +The Countess 6 +Pitspawn Fouldog 7 +Flamespike the Crawler 8 +Boneash 9 +Radament 10 +Bloodwitch the Wild 11 +Fangskin 12 +Beetleburst 13 +Leatherarm 14 +Coldworm the Burrower 15 +Fire Eye 16 +Dark Elder 17 +The Summoner 18 +Ancient Kaa the Soulless 19 +The Smith 20 +Web Mage the Burning 21 +Witch Doctor Endugu 22 +Stormtree 23 +Sarina the Battlemaid 24 +Icehawk Riftwing 25 +Ismail Vilehand 26 +Geleb Flamefinger 27 +Bremm Sparkfist 28 +Toorc Icefist 29 +Wyand Voidfinger 30 +Maffer Dragonhand 31 +Winged Death 32 +The Tormentor 33 +Taintbreeder 34 +Riftwraith the Cannibal 35 +Infector of Souls 36 +Lord De Seis 37 +Grand Vizier of Chaos 38 +The Cow King 39 +Corpsefire 40 +The Feature Creep 41 + +Siege Boss 42 +Ancient Barbarian 1 43 +Ancient Barbarian 2 44 +Ancient Barbarian 3 45 +Axe Dweller 46 +Bonesaw Breaker 47 +Dac Farren 48 +Megaflow Rectifier 49 +Eyeback Unleashed 50 +Threash Socket 51 +Pindleskin 52 +Snapchip Shatter 53 +Anodized Elite 54 +Vinvear Molech 55 +Sharp Tooth Sayer 56 +Magma Torquer 57 +Blaze Ripper 58 +Frozenstein 59 +Nihlathak 60 +Baal Subject 1 61 +Baal Subject 2 62 +Baal Subject 3 63 +Baal Subject 4 64 +Baal Subject 5 65 diff --git a/d2bs/kolbot/sdk/areas.txt b/d2bs/kolbot/sdk/areas.txt new file mode 100644 index 000000000..0824f64b7 --- /dev/null +++ b/d2bs/kolbot/sdk/areas.txt @@ -0,0 +1,137 @@ +0 = None +1 = Rogue Encampment +2 = Blood Moor +3 = Cold Plains +4 = Stony Field +5 = Dark Wood +6 = Black Marsh +7 = Tamoe Highland +8 = Den Of Evil +9 = Cave Level 1 +10 = Underground Passage Level 1 +11 = Hole Level 1 +12 = Pit Level 1 +13 = Cave Level 2 +14 = Underground Passage Level 2 +15 = Hole Level 2 +16 = Pit Level 2 +17 = Burial Grounds +18 = Crypt +19 = Mausoleum +20 = Forgotten Tower +21 = Tower Cellar Level 1 +22 = Tower Cellar Level 2 +23 = Tower Cellar Level 3 +24 = Tower Cellar Level 4 +25 = Tower Cellar Level 5 +26 = Monastery Gate +27 = Outer Cloister +28 = Barracks +29 = Jail Level 1 +30 = Jail Level 2 +31 = Jail Level 3 +32 = Inner Cloister +33 = Cathedral +34 = Catacombs Level 1 +35 = Catacombs Level 2 +36 = Catacombs Level 3 +37 = Catacombs Level 4 +38 = Tristram +39 = Moo Moo Farm +40 = Lut Gholein +41 = Rocky Waste +42 = Dry Hills +43 = Far Oasis +44 = Lost City +45 = Valley Of Snakes +46 = Canyon Of The Magi +47 = A2 Sewers Level 1 +48 = A2 Sewers Level 2 +49 = A2 Sewers Level 3 +50 = Harem Level 1 +51 = Harem Level 2 +52 = Palace Cellar Level 1 +53 = Palace Cellar Level 2 +54 = Palace Cellar Level 3 +55 = Stony Tomb Level 1 +56 = Halls Of The Dead Level 1 +57 = Halls Of The Dead Level 2 +58 = Claw Viper Temple Level 1 +59 = Stony Tomb Level 2 +60 = Halls Of The Dead Level 3 +61 = Claw Viper Temple Level 2 +62 = Maggot Lair Level 1 +63 = Maggot Lair Level 2 +64 = Maggot Lair Level 3 +65 = Ancient Tunnels +66 = Tal Rashas Tomb #1 +67 = Tal Rashas Tomb #2 +68 = Tal Rashas Tomb #3 +69 = Tal Rashas Tomb #4 +70 = Tal Rashas Tomb #5 +71 = Tal Rashas Tomb #6 +72 = Tal Rashas Tomb #7 +73 = Duriels Lair +74 = Arcane Sanctuary +75 = Kurast Docktown +76 = Spider Forest +77 = Great Marsh +78 = Flayer Jungle +79 = Lower Kurast +80 = Kurast Bazaar +81 = Upper Kurast +82 = Kurast Causeway +83 = Travincal +84 = Spider Cave +85 = Spider Cavern +86 = Swampy Pit Level 1 +87 = Swampy Pit Level 2 +88 = Flayer Dungeon Level 1 +89 = Flayer Dungeon Level 2 +90 = Swampy Pit Level 3 +91 = Flayer Dungeon Level 3 +92 = A3 Sewers Level 1 +93 = A3 Sewers Level 2 +94 = Ruined Temple +95 = Disused Fane +96 = Forgotten Reliquary +97 = Forgotten Temple +98 = Ruined Fane +99 = Disused Reliquary +100 = Durance Of Hate Level 1 +101 = Durance Of Hate Level 2 +102 = Durance Of Hate Level 3 +103 = The Pandemonium Fortress +104 = Outer Steppes +105 = Plains Of Despair +106 = City Of The Damned +107 = River Of Flame +108 = Chaos Sanctuary +109 = Harrogath +110 = Bloody Foothills +111 = Frigid Highlands +112 = Arreat Plateau +113 = Crystalized Passage +114 = Frozen River +115 = Glacial Trail +116 = Drifter Cavern +117 = Frozen Tundra +118 = Ancient's Way +119 = Icy Cellar +120 = Arreat Summit +121 = Nihlathaks Temple +122 = Halls Of Anguish +123 = Halls Of Pain +124 = Halls Of Vaught +125 = Abaddon +126 = Pit Of Acheron +127 = Infernal Pit +128 = The Worldstone Keep Level 1 +129 = The Worldstone Keep Level 2 +130 = The Worldstone Keep Level 3 +131 = Throne Of Destruction +132 = The Worldstone Chamber +133 = Matron's Den +134 = Fogotten Sands +135 = Furnace of Pain +136 = Tristram diff --git a/d2bs/kolbot/sdk/basestats.txt b/d2bs/kolbot/sdk/basestats.txt new file mode 100644 index 000000000..4b34ebe2b --- /dev/null +++ b/d2bs/kolbot/sdk/basestats.txt @@ -0,0 +1,90 @@ +0 AlternateGfx (this is actually a 3-4 letter word) +1 WeaponClass (this is actually a 3-4 letter word) +2 TwoHandedWeaponClass (this is actually a 3-4 letter word) +3 +4 MinAC +5 MaxAC +6 BaseGambleCost +7 BaseAttackSpeed +8 DurabilityWarning (ItemRarity in weapons?) +9 BaseCost +10 +11 +12 +13 +14 (always FFFFFFFF, probably just a terminator between the DWORDs and single BYTEs) +15 Version (64 for xpac, 0 for norm) +16 +17 +18 +19 +20 +21 ItemRarity +22 BaseItemLevel +23 MinDmg (also applies to shields dmg) +24 MaxDmg (also applies to shields dmg) +25 +26 +27 MinTwoHandDmg +28 MaxTwoHandDmg +29 AttackRange +30 StrBonus +31 DexBonus +32 StrReq +33 DexReq +34 +35 SizeX +36 SizeY +37 BaseBlock +38 BaseDurability +39 +40 +41 Component +42 +43 +44 +45 +46 +47 +48 TwoHanded +49 +50 Type +51 (255 in weapons?) +52 +53 SoundId +54 +55 Quest +56 +57 TransTable +58 +59 LightRadius +60 +61 +62 +63 +64 +65 DurationWarningWep +66 +67 +68 MaxSockets +69 +70 +71 +72 +73 +74 +75 BaseLevelReq +76 MagicLvl +77 Transform +78 InvTrans +79 + +.. + +167 Last few of these are probably the NPC sell values (all seem to be 255, which is what it is in the mpq) + + +Initial compilation done by njaguar + +Feel free to update this as you discover (definitively) new values. Please post updates (just the new fields, or changes) +to the forums. diff --git a/d2bs/kolbot/sdk/bodylocations.txt b/d2bs/kolbot/sdk/bodylocations.txt new file mode 100644 index 000000000..d2c438dc1 --- /dev/null +++ b/d2bs/kolbot/sdk/bodylocations.txt @@ -0,0 +1,13 @@ +#define BODYLOC_NONE 0 +#define BODYLOC_HEAD 1 +#define BODYLOC_NECK 2 +#define BODYLOC_TORSO 3 +#define BODYLOC_RIGHT_ARM 4 +#define BODYLOC_LEFT_ARM 5 +#define BODYLOC_RIGHT_RING 6 +#define BODYLOC_LEFT_RING 7 +#define BODYLOC_BELT 8 +#define BODYLOC_FEET 9 +#define BODYLOC_GLOVES 10 +#define BODYLOC_RIGHT_ARM_SECONDARY 11 +#define BODYLOC_LEFT_ARM_SECONDARY 12 diff --git a/d2bs/kolbot/sdk/commandRef.htm b/d2bs/kolbot/sdk/commandRef.htm new file mode 100644 index 000000000..8e923ed84 --- /dev/null +++ b/d2bs/kolbot/sdk/commandRef.htm @@ -0,0 +1,1622 @@ +d2jsp Command Reference

d2jsp Command Reference:

+ area [Object]
+ area.exits;
+ area.name;
+ area.x;
+ area.xsize;
+ area.y;
+ area.ysize;
+ control [Object]
+ control.click( );
+ control.getNext( );
+ control.getText( );
+ control.setText( );
+ control.disabled;
+ control.maxlength;
+ control.text;
+ control.type;
+ control.visible;
+ control.x;
+ control.xsize;
+ control.y;
+ control.ysize;
+ file [Object]
+ file.close( );
+ file.flush( );
+ file.getc( );
+ file.putc( );
+ file.readLine( );
+ file.seek( );
+ file.writeLine( );
+ file.eof;
+ file.pos;
+ party [Object]
+ party.getNext( );
+ party.area;
+ party.gid;
+ party.level;
+ party.life;
+ party.name;
+ party.partyflag;
+ party.partyid;
+ party.x;
+ party.y;
+ presetunit [Object]
+ presetunit.id;
+ presetunit.roomid;
+ presetunit.roomx;
+ presetunit.roomy;
+ presetunit.type;
+ presetunit.x;
+ presetunit.y;
+ room [Object]
+ room.getCollision( );
+ room.getFirst( );
+ room.getNearby( );
+ room.getNext( );
+ room.getPresetUnits( );
+ room.getStat( );
+ room.unitInRoom( );
+ room.correcttomb;
+ room.level;
+ room.levelx;
+ room.levely;
+ room.number;
+ room.subnumber;
+ room.type;
+ room.x;
+ room.y;
+ screen [Object]
+ screen.sendToBack( );
+ screen.sendToFront( );
+ screen.color;
+ screen.font;
+ screen.image;
+ screen.opacity;
+ screen.text;
+ screen.type;
+ screen.x;
+ screen.x2;
+ screen.y;
+ screen.y2;
+ script [Object]
+ script.getNext( );
+ script.send( );
+ script.stop( );
+ script.abort;
+ script.gametype;
+ script.name;
+ script.running;
+ script.threadid;
+ unit [Object]
+ unit.cancel( );
+ unit.getEnchant( );
+ unit.getFlag( );
+ unit.getFreeSpace( );
+ unit.getItemCost( );
+ unit.getItems( );
+ unit.getMinionCount( );
+ unit.getNearUnits( );
+ unit.getNext( );
+ unit.getParent( );
+ unit.getSkill( );
+ unit.getSkillDamageMax( );
+ unit.getSkillDamageMin( );
+ unit.getStat( );
+ unit.getState( );
+ unit.getStatEx( );
+ unit.interact( );
+ unit.move( );
+ unit.overhead( );
+ unit.repair( );
+ unit.setSkill( );
+ unit.shop( );
+ unit.useMenu( );
+ unit.useSkill( );
+ unit.useSkillAt( );
+ unit.act;
+ unit.area;
+ unit.classid;
+ unit.code;
+ unit.description;
+ unit.fname;
+ unit.gid;
+ unit.hp;
+ unit.hpmax;
+ unit.ilvl;
+ unit.itemclass;
+ unit.itemid;
+ unit.itemloc;
+ unit.itemtype;
+ unit.lvlreq;
+ unit.mode;
+ unit.mp;
+ unit.mpmax;
+ unit.name;
+ unit.owner;
+ unit.ownertype;
+ unit.pid;
+ unit.pname;
+ unit.prefix;
+ unit.quality;
+ unit.runeword;
+ unit.sid;
+ unit.spectype;
+ unit.state;
+ unit.status;
+ unit.subarea;
+ unit.suffix;
+ unit.type;
+ unit.usable;
+ unit.x;
+ unit.xsize;
+ unit.y;
+ unit.ysize;
+ me [Global Object]
+ me.language [Object]
+ me.getQuest( );
+ me.account;
+ me.charname;
+ me.chickenhp;
+ me.chickenmp;
+ me.diff;
+ me.gamefilename;
+ me.gamelength;
+ me.gamename;
+ me.gamepassword;
+ me.gameserverip;
+ me.gamestarttime;
+ me.gametype;
+ me.golddialog;
+ me.ingame;
+ me.ip;
+ me.itemoncursor;
+ me.ladder;
+ me.lasterror;
+ me.logchicken;
+ me.logquit;
+ me.logtimeout;
+ me.mercnamestr;
+ me.mercrevive;
+ me.minimized;
+ me.miscscreenmode;
+ me.ping;
+ me.pingtimer;
+ me.playertype;
+ me.quitonerror;
+ me.quitonhostile;
+ me.quitscriptend;
+ me.randommove;
+ me.realm;
+ me.realmshort;
+ me.runwalk;
+ me.screensize;
+ me.showexp;
+ me.showlifeorb;
+ me.showmanaorb;
+ me.skip;
+ me.version;
+ me.windowtitle;
Global Functions
+ acceptTrade( );
+ beep( );
+ blockEvent( );
+ blockMinimize( );
+ checkCollision( );
+ clickItem( );
+ clickMap( );
+ clickParty( );
+ copyUnit( );
+ createDirectory( );
+ delay( );
+ fileOpen( );
+ getArea( );
+ getBaseStat( );
+ getCursorType( );
+ getDistance( );
+ getLocaleString( );
+ getMouseCoords( );
+ getMyPID( );
+ getParty( );
+ getPath( );
+ getPlayerFlag( );
+ getPresetUnits( );
+ getRating( );
+ getRepairCost( );
+ getRoom( );
+ getScreenHook( );
+ getScript( );
+ getTextWidthHeight( );
+ getThreadPriority( );
+ getTickCount( );
+ getTradeInfo( );
+ getUIFlag( );
+ getUnit( );
+ getWaypoint( );
+ gold( );
+ include( );
+ isIncluded( );
+ load( );
+ playSound( );
+ print( );
+ quit( );
+ quitGame( );
+ registerEvent( );
+ rnd( );
+ runGC( );
+ say( );
+ scriptBroadcast( );
+ sendCopyData( );
+ sendDDE( );
+ sendSound( );
+ setMinimized( );
+ setThreadPriority( );
+ stop( );
+ submitItem( );
+ takeScreenshot( );
+ transmute( );
+ useSkillPoint( );
+ useStatPoint( );
+ weaponSwitch( );
Constants
+ EVENT_AREACHANGE;
+ EVENT_CHATMSG;
+ EVENT_COPYDATA;
+ EVENT_GAMEMSG;
+ EVENT_HOSTILEMSG;
+ EVENT_INPUTLINE;
+ EVENT_ITEMSTAT;
+ EVENT_KEYDOWN;
+ EVENT_KEYUP;
+ EVENT_MELIFE;
+ EVENT_MISSILEMOVE;
+ EVENT_MISSILESTATE;
+ EVENT_MOUSEDOWN;
+ EVENT_MOUSEUP;
+ EVENT_NEWITEM;
+ EVENT_NEWNPC;
+ EVENT_NPCLIFE;
+ EVENT_NPCMOVE;
+ EVENT_NPCSTAT;
+ EVENT_NPCSTATE;
+ EVENT_PARTYMSG;
+ EVENT_PLAYERMOVE;
+ EVENT_PLAYERSTAT;
+ EVENT_PLAYERSTATE;
+ EVENT_QUEST;
+ EVENT_SCRIPTMSG;
+ EVENT_UNITMOVE;
+ EVENT_WINDOWFOCUS;

Global Objects:

+
 
Summary: Holds Area Information
Description:
Area object, holds information about the area
Usable: [In Game]

 Properties:

+
 
Summary: Gets a list of the exits for this Area
Description:
Returns an array of area id's that the area links to.
+Note: Does not show ANY red portals!
Usable: [In Game]
+
 
Summary: Name of the Area
Description:
Returns the name of the area
Usable: [In Game]
+
 
Summary: Start X Coordinate of the Area
Description:
starting x coordinate of the area.
+Note: You need to *5 this value for the actual ingame size.
Usable: [In Game]
+
 
Summary: X Size of the Area
Description:
x size of the area
+Note: You need to *5 this value for the actual ingame size.
Usable: [In Game]
+
 
Summary: Start Y Coordinate of the Area
Description:
starting y coordinate of the area.
+Note: You need to *5 this value for the actual ingame size.
Usable: [In Game]
+
 
Summary: Y Size of the Area
Description:
y size of the area
+Note: You need to *5 this value for the actual ingame size.
Usable: [In Game]
+
 
Summary:
Description:
Usable: [Out of Game]

 Functions:

+
 
Summary:
Description:
Clicks a control
+
+If x and y are specified, clicks a specific spot within a control (ie, listbox)
Usable: [Out of Game]
+
 
Summary:
Description:
Usable: [Out of Game]
+
 
Summary: Gets the controls extended text
Description:
Gets the controls extended text, in a string array
Usable: [Out of Game]
+
 
Summary: Sets the controls text
Description:
Sets the controls text (edit box)
Usable: [Out of Game]

 Properties:

+
 
Summary: Returns whether a control is disabled or not
Description:
Returns whether a control is disabled or not
Usable: [Out of Game]
+
 
Summary: Returns the max length an edit box will accept.
Description:
Returns the max length an edit box will accept for a string
+
+**Note: This includes the null terminator, so for script purposes you need to subtract 1 from this value.
Usable: [Out of Game]
+
 
Summary:
Description:
Usable: [Out of Game]
+
 
Summary:
Description:
Usable: [Out of Game]
+
 
Summary: Returns whether control is visible
Description:
Returns true if a control is visible, or false if it is hidden
Usable: [Out of Game]
+
 
Summary:
Description:
Usable: [Out of Game]
+
 
Summary:
Description:
Usable: [Out of Game]
+
 
Summary:
Description:
Usable: [Out of Game]
+
 
Summary:
Description:
Usable: [Out of Game]
+
 
Summary: The file object handle.
Description:
Points to a file opened with fileOpen()
Usable: [In Game] [Out of Game]

 Functions:

+
 
Summary: Closes a file that was opened
Description:
This will close the file that you opened with openFile()
+
+Once the file is closed, you may no longer read or write to it, and file will be equal to 0 (null)
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary: Gets the next character
Description:
Gets the next character on the file stream
+Most useful for binary reading
Usable: [In Game] [Out of Game]
+
 
Summary: Puts a character into a file
Description:
Puts a character into the file stream. Pass multiple integers to insert multiple characters in one call.
+Most useful for binary writing
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]

 Properties:

+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary: Returns the file byte position
Description:
Returns the file byte position shown by ftell()
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game]

 Functions:

+
 
Summary:
Description:
Usable: [In Game]

 Properties:

+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: Returns the party button status
Description:
Returns the following values:
+    0 = Invite (no invites for this person, invite them to the party)
+    1 = None (cannot invite this person, they are already in a party, or this is you)
+    2 = Accept (they invited you)
+    4 = Cancel (you invited them)
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: X Location of the player
Description:
Returns the X location of the party player
Usable: [In Game]
+
 
Summary: Y Location of the player
Description:
Returns the Y location of the party player
Usable: [In Game]
+
 
Summary: Gets a preset unit that always exists in every game
Description:
PresetUnits are NPCs, objects and tiles in the map which are known by the game as long as you stay in a specific act. Querying presetunits is the way to find out the placement of WPs, NPCs, doors, tiles, chests, etc,
+in the map without the needing to be near them.
+Barrels, baskets, chests, etc. are not presetunits.
+
+The position of presetunits may change while the game is running (i.e. NPCs). In that case, the position you get by doing a look up of the presetunit is only a hint, where the unit is. In practice you will move to the position of the
+presetunit and than you can look up the life unit with getUnit(); to get the current position of the unit.
Usable: [In Game]

 Properties:

+
 
Summary: Class Id of the presetunit
Description:
presetunit.id is a numeric value representing the classid of a specific presetunit.
Usable: [In Game]
+
 
Summary: The room number the presetunit resides in
Description:
presetunit.roomid is a numeric value representing the room number where the specific presetunit is in.
+
+It is the same number as you get by room.number, and it is the number you maybe want to give to the roomarray parameter of getPresetUnits().
Usable: [In Game]
+
 
Summary: Returns the X coordinate of the room the presetunit resides in
Description:
presetunit.roomx is a numeric value representing the x-coordinate divided by 5 of the room (not of the unit itself) where the specific presetunit is in.
+
+To get the absolute x-coordinate of the concerned room (not of the unit) you have to multiply this value by 5.
Usable: [In Game]
+
 
Summary: Returns the Y coordinate of the room the presetunit resides in
Description:
presetunit.roomy is a numeric value representing the y-coordinate divided by 5 of the room (not of the unit itself) where the specific presetunit is in.
+
+To get the absolute y-coordinate of the concerned room (not of the unit) you have to multiply this value by 5.
Usable: [In Game]
+
 
Summary: Returns the type of the presetunit
Description:
presetunit.type is a numeric value representing unit type of concerned presetunit. Possible types are:
+
+Type 0 is Player
+Type 1 is Monster/NPC
+Type 2 is Object
+Type 3 is Missile
+Type 4 is Item
+Type 5 is Tile
+
+Practically presetunits are only NPCs, Objects and Tiles.
Usable: [In Game]
+
 
Summary: Returns the X coordinate of the in room location of the unit.
Description:
presetunit.x is a numeric value representing the x-coordinate of the presetunit relative to the rooms x-coordinate where the presetunit is in.
+
+To get the absolute x-coordinate of the presetunit you have to add the absolute x-coordinate of the room (presetunit.roomx)
Usable: [In Game]
+
 
Summary: Returns the Y coordinate of the in room location of the unit.
Description:
presetunit.y is a numeric value representing the y-coordinate of the presetunit relative to the rooms y-coordinate where the presetunit is in.
+
+To get the absolute y-coordinate of the presetunit you have to add the absolute y-coordinate of the room (presetunit.roomy)
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]

 Functions:

+
 
Summary:
Description:
room.getCollision() with no params will return a two dimensional array with all the collision values for the room
+
+room.getCollision( 1 ); // returns ?? (i forget, will figure this out later :)
+
+room.getCollision(x, y); // returns the collision table value for XY coord. of the room
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: Returns nearby rooms
Description:
Returns an array of rooms that are near to this room (surrounding rooms.)
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
room.getPresetUnits([type],[id]); // This returns an ARRAY of presetunit objects!
+        Params: Type will specify what type to return; ID will specify only what id's to return
+        presetunit Object Properties: presetunit.id, presetunit.type, presetunit.x, presetunit.y
+        **Note: In order to get presetunits for far away rooms, you will likely have to initialize/release the room(s)
Usable: [In Game]
+
 
Summary:
Description:
see roomstats.txt for more info
Usable: [In Game]
+
 
Summary: Returns true or false, depending if the unit is in the room or not.
Description:
Returns true or false, depending if the unit is in the room or not.
+
+Note: Works for all unit types, players, items, objects, etc
Usable: [In Game]

 Properties:

+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: This is the areaId of the room
Description:
This is the areaId of the room. Check out sdk/areas.txt for a full list of area ids.
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
If a room has a type of 1, it will return -1 for room.number and room.subnumber
Usable: [In Game]
+
 
Summary:
Description:
If a room has a type of 1, it will return -1 for room.number and room.subnumber
Usable: [In Game]
+
 
Summary: Returns the Preset Type Id
Description:
Returns the Preset Type Id
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]

 Functions:

+
 
Summary: draws the screenhook on the bottom
Description:
Causes the z-order of the screenhook to be the first drawn (on bottom)
Usable: [In Game] [Out of Game]
+
 
Summary: draws the screenhook on top
Description:
Causes the z-order of the screenhook to be the last drawn (on top)
Usable: [In Game] [Out of Game]

 Properties:

+
 
Summary:
Description:
Color Chart:
+
0123456789ABCDEF
0                
1                
2                
3                
4                
5                
6                
7                
8                
9                
A                
B                
C                
D                
F 

+
+As of 0.41, this is a write only property
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Here is a sample screenshot of what the fonts look like:
+
+
+As of 0.41, this is a write only property
Usable: [In Game] [Out of Game]
+
 
Summary: Sets an image associated with a screenhook
Description:
You can now set a bmp screenhook image. Be sure to set the screenhook type to 2 (IMAGE).
+
+Note: So far, only supports bitmaps.
+
+As of 0.42, this value is write only.
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
opacity of object, 0 = transparent, 0xff = opaque, default is 0xff
+
+As of 0.41, this is a write only property
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
As of 0.41, this is a write only property
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
0 = line
+1 = box
+2 = image (added in 0.42)
+
+As of 0.41, this is a write only property
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
As of 0.41, this is a write only property
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
As of 0.41, this is a write only property
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
As of 0.41, this is a write only property
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
As of 0.41, this is a write only property
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game]

 Functions:

+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]

 Properties:

+
 
Summary: Returns whether a script is set to abort (stop) or not.
Description:
Returns whether a script is set to abort (stop) or not.
+
+**Note: This is a debug value
Usable: [In Game] [Out of Game]
+
 
Summary: Returns the gametype of the script
Description:
Returns the gametype of the script:
+
+0 - In Game
+1 - Out of Game
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary: Returns the threadId of the executing script
Description:
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Base Game Unit:
+Type 0 is Player
+Type 1 is Monster/NPC
+Type 2 is Object
+Type 3 is Missile
+Type 4 is Item
+Type 5 is Tile
Usable: [In Game]

 Functions:

+
 
Summary: Cancels certain dialog windows/actions
Description:
If holding an item on cursor, drops item to ground.
+
+Otherwise, passing:
+0 - Cancel Dialog (windows with close buttons)
+1 - Cancel NPC (menus, gossip chats)
Usable: [In Game]
+
 
Summary: Get a monsters Enchantment
Description:
Get a monsters enchantment. Returns true or false if the enchantment is on the unit.
+
+**Note: see enchants.txt for a list of enchantments
Usable: [In Game]
+
 
Summary: Returns if a flag is set on an item
Description:
Returns value for flag passed, depending if flag is set on item or not
+
+**Note: See itemflags.txt for full list of flags
Usable: [In Game]
+
 
Summary: Finds a free spot for the item
Description:
Returns a 2 element array with the xy where the item will fit.
+
+Notes: Returns -1,-1 if no room in the location.
+
+Locations: 0 = inventory, 2 = player trade, 3 = cube, 4 = stash
Usable: [In Game]
+
 
Summary: Returns NPC cost of an item
Description:
Returns NPC cost of an item
+
+If npcClassId is not specified, uses Act V npc.
+
+Modes:
+0 - Buying From NPC
+1 - Selling To NPC
+2 - Repair Cost
Usable: [In Game]
+
 
Summary: Returns all the items a unit owns
Description:
Returns an array of all the items that belong to 'unit'.
+
+Note: This works for players, NPCs, and even other items (ie, contains socketed gems/jewels/runes)
Usable: [In Game]
+
 
Summary: returns the # of minions of this type you currently have
Description:
Returns the # of minions of this type you currently have
+
+Here's the ID list taken from PetType table:
+pet type        idx
+none            0
+single        1
+valkyrie        2
+golem            3
+skeleton        4
+skeletonmage    5
+revive        6
+hireable        7
+dopplezon        8
+invis            9
+raven            10
+spiritwolf        11
+fenris        12
+totem            13
+vine            14
+grizzly        15
+shadowwarrior    16
+assassintrap    17
+pettrap        18
+hydra            19
Usable: [In Game]
+
 
Summary: Returns an array of units within X range of the unit used.
Description:
Returns an array of units within X range of the unit used.
+
+Note: You can specify a direct mode or modemask, see getUnit() for more info.
+
+Note: You can specify a collision flag between unit and dest. Equiv to checkCollision(unit,unit,collisionBitmask)
+
+Note: You can turn off the sorting by lowest dist first by passing true as the last param.
+
+Note: Pass null to any of the last 3 optional params to not use them.
Usable: [In Game]
+
 
Summary: Gets next Unit
Description:
See description of getUnit() for what these parameters mean. You do NOT pass Type to getNext.
+
+**Note: If you want to iterate over a specific unit search, and are using the 2nd/3rd/4th params on getUnit, you must also pass them to getNext()
+If you only passed Type to getUnit, you do not need to pass any parameters to getNext()
Usable: [In Game]
+
 
Summary: Returns the parent unit
Description:
Returns the parent unit, or null if there is no parent
Usable: [In Game]
+
 
Summary: Gets Skill Info
Description:
Gets Skill Info based upon the mode:
+0 - Right Hand Skill Name
+1 - Left Hand Skill Name
+2 - Right Hand Skill Id
+3 - Left Hand Skill Id
+
+** If you use getSkillLevel, use SkillID instead of the above mode list to get the getSkillLevel info
+
+getSkillLevel:
+0 - will return the full skill level, all +skills calculated
+1 - will return only the base level of the skill (no bonus to skills added)
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: Gets a Unit Stat
Description:
Gets a Unit Stat
+
+Pass subindex to get a sub index stat: eg; class specific skill bonus
+
+For index:
+Pass -1: returns an array of all stats in the format: [statindex, substatindex, value];
+
+Pass -2: returns a complete list of all the stats and substats a unit has. Use this to get an associate array listing of all stats a unit has. Example return for +10 energy item:
+print(retval[1][0]); would be 10 (stat 1 is energy, substat value 0).
+- See tools/statEnumerator.d2j for an example script on looping through all stats
+        This method will return all runeword stats on items!
Usable: [In Game]
+
 
Summary:
Description:
See states.txt for full list
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: Interacts with unit Object
Description:
Interacts with unit Object:
+
+If unit is an item, then mode is a flag to pick item up to cursor or not (from ground). eg: itemOnGround.interact(1); would pick the item up to your cursor
+
+If unit is an object (waypoint), then mode is the destination areaId you wish to travel to
+
+If unit is player: will approach them and offer trade. If a trade request is offered to YOU, use me.interact(1) or player.interact(1) and it will accept the trade request.
+
+If the unit is an npc and you pass 1, I forget what it does ;) (someone remind me)
Usable: [In Game]
+
 
Summary:
Description:
Obsolete, use clickMap()
Usable: [In Game]
+
 
Summary: Sets the Unit's overhead message
Description:
Use this to set a Units overhead message. Works for Players, NPCs or Objects.
+
+**Note: This is a clientside effect only, to send the overhead to the server, use say() command and prefix your string with a "!"
Usable: [In Game]
+
 
Summary: Repairs all equipment
Description:
Repairs all equipment
Usable: [In Game]
+
 
Summary: Sets a skill to left/right hand
Description:
Sets a skill to left/right hand
+
+Pass itemGlobalId to set skill charge/ability from an item
+
+Hand:
+0 = right
+1 = left
Usable: [In Game]
+
 
Summary: Buy/Sell/Repair Items at NPC
Description:
Buy/Sell/Repair Items at NPC
+
+mode:
+0=repair (not functional)
+1=sell
+2=buy
+
+Pass the OBJECT of the npc, ie: npc=getUnit(1, "Malah");
+item.shop(npc, 1);
+
+As of v0.50, the npc param is no longer required, and should not be used. Only use the MODE.
Usable: [In Game]
+
 
Summary: Uses an NPC menu
Description:
Uses an NPC menu, see npcmenuid.txt for a full list
Usable: [In Game]
+
 
Summary:
Description:
Obsolete, use clickMap()
Usable: [In Game]
+
 
Summary:
Description:
Obsolete, use clickMap()
Usable: [In Game]

 Properties:

+
 
Summary: Returns the Act of the unit
Description:
Returns the act the unit is in. The act is 0 base, so Act 1 will return 0
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: Unit's Class Id
Description:
Return's the units Class Id (identifier)
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: Returns the full name of an item
Description:
Will return the full name of the item, see below
+
+Magical: "prefix basename suffix"
+Rare: "prefix suffix"
+Set: Item Set Name
+Unique: Item Unique Name
+Crafted: "prefix suffix"
+
+* (null) will be returned for affixes in this if the particular affix isn't in use.
+* You will get odd results if you attempt to use this on an item type not listed above (A rune, for example)
+* Please also note that some of the affixes displayed in game are labeled differently, sort of like the variations in some skill names.
Usable: [In Game]
+
 
Summary: Global Id
Description:
The global identifier used by D2 to keep a unit sync'd with the server.
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: returns the Set or Unique ID of the item
Description:
returns the Set or Unique ID of the item (used with getBaseStat()
+
+Only applies to Set or Unique items.
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: Generic type of the item
Description:
Only applies to items!
+
+Values of item.itemtype:
+
 0: None                         
+ 1: None
+ 2: Shield shie *
+ 3: Armor tors *
+ 4: Gold gold
+ 5: Bow Quiver bowq *
+ 6: Crossbow Quiver xboq *
+ 7: Player Body Part play
+ 8: Herb herb
+ 9: Potion poti
+10: Ring ring *
+11: Elixir elix
+12: Amulet amul *
+13: Charm char
+14: Not Used
+15: Boots boot *
+16: Gloves glov *
+17: Not Used
+18: Book book * TP Tome
+19: Belt belt *
+20: Gem gem
+21: Torch torc
+22: Scroll scro
+23: Not Used
+24: Scepter scep
+25: Wand wand
+26: Staff staf
+27: Bow bow *
+28: Axe axe
+29: Club club
+30: Sword swor *
+31: Hammer hamm
+32: Knife knif
+33: Spear spea
+34: Polearm pole
+35: Crossbow xbow *
+36: Mace mace
+37: Helm helm *
+38: Missile Potion tpot
+39: Quest ques * Cube
+40: Body Part body
+41: Key key
+42: Throwing Knife tkni
+43: Throwing Axe taxe
+44: Javelin jave
+45: Weapon weap
+46: Melee Weapon mele
+47: Missile Weapon miss
+48: Thrown Weapon thro
+49: Combo Weapon comb
+50: Any Armor armo
+51: Any Shield shld
+52: Miscellaneous misc
+53: Socket Filler sock
+54: Second Hand seco
+55: Staves And Rods rod
+56: Missile misl
+57: Blunt blun
+58: Jewel jewl *
+59: Class Specific clas
+60: Amazon Item amaz
+61: Barbarian Item barb
+62: Necromancer Item necr
+63: Paladin Item pala
+64: Sorceress Item sorc
+65: Assassin Item assn
+66: Druid Item drui
+67: Hand to Hand h2h
+68: Orb orb *
+69: Voodoo Heads head
+70: Auric Shields ashd
+71: Primal Helm phlm * Arreat's Face
+72: Pelt pelt
+73: Cloak cloa
+74: Rune rune *
+75: Circlet circ
+76: Healing Potion hpot
+77: Mana Potion mpot
+78: Rejuv Potion rpot *
+79: Stamina Potion spot
+80: Antidote Potion apot
+81: Thawing Potion wpot
+82: Small Charm scha * Small Charm
+83: Medium Charm mcha * Large Charm
+84: Large Charm lcha * Grand Charm
+85: Amazon Bow abow
+86: Amazon Spear aspe
+87: Amazon Javelin ajav
+88: Hand to Hand 2 h2h2
+89: Magic Bow Quiv mboq
+90: Magic Xbow Quiv mxbq
+91: Chipped Gem gem0
+92: Flawed Gem gem1
+93: Standard Gem gem2
+94: Flawless Gem gem3
+95: Perfect Gem gem4
+96: Amethyst gema
+97: Diamond gemd
+98: Emerald geme
+99: Ruby gemr
+100: Sapphire gems
+101: Topaz gemt
+102: Skull gemz

+

Values with an * have been confirmed as a used value. Some of the codes are unused in-game.

Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: Returns the name of the unit
Description:
Returns a string holding the name of the unit. This is unicode compatable, as applicable.
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: Returns owner type of a missile
Description:
Returns the owner type of a missile (0 player, 1 npc/monster)
Usable: [In Game]
+
 
Summary: Returns the prefix ID for an item.
Description:
Returns the prefix ID for a magical item.
+
+OR
+
+Returns an array of 4 prefix IDs for rares and crafted, 1st # will be the Rare/Crafted Name Prefix ID, last 3 are the actual magical prefix IDs
Usable: [In Game]
+
 
Summary: Returns the Personalized Name of an item
Description:
Returns the Personalized Name of an item, or blank if none.
Usable: [In Game]
+
 
Summary: Returns prefix name of item
Description:
Returns prefix name of item (magical or rare or crafted only)
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: Returns the runeword name of an item
Description:
Returns the runeword name of an item (if one exists)
+Don't rely exclusively on this, make sure to check the flag on this to make sure it's a runeword!
Usable: [In Game]
+
 
Summary: Returns the suffix ID for an item
Description:
Returns the suffix ID for a magical item.
+
+OR
+
+Returns an array of 4 suffix IDs for rares and crafted, 1st # will be the Rare/Crafted Name Suffix ID, last 3 are the actual magical suffix IDs
Usable: [In Game]
+
 
Summary: Determines the spectype of a monster
Description:
Returns the following in a bitmask form:
+0x00    Normal Monster
+0x01    Super Unique
+0x02    Champion
+0x04    Boss
+0x08    Minion
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: Returns suffix name of item
Description:
Returns suffix name of item (magical or rare or crafted only)
Usable: [In Game]
+
 
Summary: Returns the type of the unit
Description:
Returns the type of the unit:
+
+0 - Player
+1 - Monster/NPC
+2 - Object
+3 - Missile
+4 - Item
+5 - Tile
Usable: [In Game]
+
 
Summary: Determines if an item is usable by your character
Description:
Returns 0 if you can use/equip this item, non-zero if you can't.
+
+Notes: The return value is a bitmask of the following:
+0 = Usable, 1 = Not Usable, 2 = Strength Too Low, 4 = Dexterity Too Low, 8 = Level Too Low
+
+Example: Item has too high str/dex reqs, so the return value will be: 1+2+4 = 7
+
+Example: Item has too high level req: return value is 9 (1+8)
+
+Example: Item has too high dex req, return value is 5 (1+4)
Usable: [In Game]
+
 
Summary: Unit's Map X position
Description:
This value holds the units current map X coordinate.
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: Unit's Map Y Position
Description:
This value holds the units current map Y coordinate.
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]

Global Globals:

+
 
Summary: Global collection that holds values specific to the current player/account.
Description:
Global collection that holds values specific to the current player/account.
+
+**Note: This global inherits all User Type methods and properties of the Unit object.
Usable: [In Game] [Out of Game]

 Objects:

+
 
Summary: Returns the current locale language
Description:
Returns the current locale language that the D2 is running.
+
+Note: Returns the 3 letter code Blizzard uses, eg: ENG for English
Usable: [In Game] [Out of Game]

 Functions:

+
 
Summary: Returns Quest Info
Description:
Here's some of the info you can get:
+
+Act 1:
+0: spoke to akara at start of game
+1: den
+2: blood raven
+4: cain
+6: andy
+
+Act 2:
+7: in act 2
+8: spoke to atma at the start of act 2
+11: got cube, staff and amulet
+12: summoner (must open red portal)
+13: spoke to townsfolk
+14: killed duriel
+
+Act 3:
+15: in act 3
+16: unknow, but activated once in act 3
+17: book
+18: smashed orb
+19: gidbin
+21: council
+22: killed meph
+
+Act 4:
+23: in act 4
+24: spoke to tyrael
+25: izzy
+26: soulstone
+27: diablo
+
+Act 5:
+28: in act 5
+35: shenk (made socket)
+36: freed soldiers
+37: anya
+38: nihlathak (personalized item)
Usable: [In Game]

 Properties:

+
 
Summary: BattleNet Account Name
Description:
Holds the account name of the currently logged in account.
Usable: [In Game] [Out of Game]
+
 
Summary: Returns the current character name
Description:
Returns the currently (or last) selected character name that was selected for login on Battle.net
+
+Note: Primary use is out of game, though it also works in game
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
As of 0.41, this is a write only value
Usable: [In Game]
+
 
Summary:
Description:
As of 0.41, this is a write only value
Usable: [In Game]
+
 
Summary: Returns the current difficulty
Description:
me.diff is a numeric value representing the difficulty of the current game.
+
+Possible values are:
+    0 - normal
+    1 - nightmare
+    2 - hell
Usable: [In Game]
+
 
Summary: Holds the script filename to execute on game start
Description:
Holds the script filename that executes on game start, can be set or get. Use this to override the default.d2j default setting.
Usable: [In Game] [Out of Game]
+
 
Summary: Game Length to Auto Quit
Description:
Time Limit (in milliseconds) to allow game to reach before core auto quits the game for you
+
+As of 0.41, this is a write only value
Usable: [In Game]
+
 
Summary: Returns the Game Name
Description:
me.gamename is a string value representing the name of the current game.
Usable: [In Game]
+
 
Summary: Returns the Game Password
Description:
me.gamepassword is a string value representing the password of the current game.
Usable: [In Game]
+
 
Summary: Returns the IP of the current game server
Description:
me.gameserverip is a string value representing the IP-address of the server which is hosting the current game.
Usable: [In Game]
+
 
Summary: Returns the GetTickCount of when you joined the game
Description:
me.gamestarttime is a numeric value representing the time stamp in ms taken from getTickCount() when the current game was joined by you.
+
+Remarks:
+If you attach d2jsp mid game, the gamestarttime will represent the time d2jsp was attached.
Usable: [In Game] [Out of Game]
+
 
Summary: Returns whether the game is Classic or LOD
Description:
me.gametype is a numeric value representing the type of the game you are in. You may say also, it result in false for classic Diablo, and in true for LoD.
+
+Possible values are:
+    0 = false - Diablo 2 classic
+    1 = true - Diablo 2 Lord of Destruction
Usable: [In Game]
+
 
Summary: Returns the state of the Gold Dialog
Description:
me.golddialog is a boolean value representing the status of the golddialog.
+
+Possible values are:
+    false - There is no golddialog on the screen
+    true - There is a golddialog on the screen
+
+me.golddialog recognize all four golddialogs:
+1. dropping gold from inventory to ground
+2. withdraw gold from stash to inventory
+3. deposit gold from inventory to stash
+4. withdraw gold from inventory to tradescreen
Usable: [In Game]
+
 
Summary: Returns whether in game or not
Description:
Returns true if in game, false if not in game.
Usable: [In Game] [Out of Game]
+
 
Summary: Returns your IP
Description:
me.ip is a string value representing the IP-address of your pc. This may differ from that IP-Address, what other people see from you on the internet, i.e. if you are behind a firewall or a router.
Usable: [In Game] [Out of Game]
+
 
Summary: Returns whether there is an item on your cursor or not
Description:
me.itemoncursor is a boolean value representing the status of the mousecursor.
+
+Possible values are:
+    false - There is no item at the mousecursor
+    true - There is no item at the mousecursor
+
+You get an item to the mousecursor by clicking on it while your inventory is open.
Usable: [In Game]
+
 
Summary: Determines if your character is a ladder character
Description:
Returns 0 if your character is NOT ladder, non-zero if they are.
+
+Note: Only works in game!
Usable: [In Game]
+
 
Summary: Returns the last script error
Description:
Returns the last script error that occured. Returns "" or null if no last error.
+
+**Note: Once you read (access) this, it will reset the last error to null.
+
+**Note: This is on a per script basis, you will not get errors from other scripts running.
Usable: [In Game] [Out of Game]
+
 
Summary: Log core chickens
Description:
Set to 1/true to enable logging of core chickening.
+
+Note: Logs to d2jsp.log
Usable: [In Game]
+
 
Summary: Logs quit() calls
Description:
set to 1/true to enable logging of any script using quit();
+
+Note: Logs to d2jsp.log
Usable: [In Game]
+
 
Summary: Logs core quits from me.gamelength expiring
Description:
set to 1/true to enable logging of any core quits due to me.gamelength being exceeded
+
+Note: Logs to d2jsp.log
Usable: [In Game]
+
 
Summary:
Description:
Returns the locale string Id for your hired mercenary
Usable: [In Game]
+
 
Summary: How much gold you need to revive your mercenary.
Description:
How much gold you need to revive your mercenary.
+
+Remarks: Because of a bug in diablo, this property result in a value > 0 even if you do not have a hireling. This may be, if you left the last game with a character, which has a hireling and this hireling is dead and you now joined the game with a character which never had a hireling yet.
Usable: [In Game]
+
 
Summary: Returns the D2 window is minimized state
Description:
Returns true or false if the window is minimized or not
Usable: [In Game] [Out of Game]
+
 
Summary: Returns misc screen mode information
Description:
me.miscscreenmode is a numeric value representing the status of some
+dialog-boxes / mousecursor-modes which may be actice.
+
+Possible values are:
+     1 - The NPC trade dialog is open
+     2 - The mousecursor is the buy cursor
+     3 - The mousecursor is the sell cursor
+     4 - The mousecursor is the repair cursor
+     5 - The sell/buy confirm dialog is shown
+    10 - The trade confirm dialog is shown
+    11 - The trade dialog is shown
+    12 - You stash is open / shown
Usable: [In Game]
+
 
Summary: Returns your current Ping
Description:
me.ping is a numeric value representing your current ping-value to the game-server.
Usable: [In Game]
+
 
Summary: Returns the ms since the last ping attempt
Description:
me.pingtimer is a numeric value representing a realtime ms counter of how long it's been since the last packet arrived.
Usable: [In Game]
+
 
Summary: Returns whether your char is Softcore or Hardcore
Description:
me.playertype is a numeric value representing the kind of your character / of the game:
+
+Possible values are:
+     0 = false - Softcore
+     1 = true - Hardcore
Usable: [In Game]
+
 
Summary: Will quit the game if a script error occurs
Description:
As of 0.41, this is a write only value
+
+me.quitonerror is a write only numeric value. If set to 1 (true), the core will quit the current game as soon as a error occurs in any running script. In this case, the error message can be retrieved by me.lasterror in the next game.
+If set to 0 and a script error occurs, the core will just print a message to the screen.
Usable: [In Game]
+
 
Summary: Quits the game if someone hostiles you
Description:
As of 0.41, this is a write only value
+
+me.quitonhostile is a write only numeric value. If set to 1 (true), the core will quit the current game as soon as a other player hostiles you and you are not in town.
+If set to 0 the core does nothing when somebody hostiles you.
Usable: [In Game]
+
 
Summary: Will quit the game when any script finishes
Description:
As of 0.41, this is a write only value
+
+me.quitscriptend is a write only numeric value. If set to 1 (true), the core will quit the current game as soon as any script finishes execution.
+If set to 0 the core does nothing when a script finishes execution.
Usable: [In Game]
+
 
Summary:
Description:
This is obsolete, never implemented.
+
+As of 0.41, this is a write only value
Usable: [In Game]
+
 
Summary: Returns the long realm name
Description:
me.realm is a string value representing the realm you playing on. For europe the result is is "europe.battle.net".
Usable: [In Game] [Out of Game]
+
 
Summary: Returns the short realm name
Description:
me.realmshort is a string value representing the realm you playing on. For europe the result is "Europe".
Usable: [In Game] [Out of Game]
+
 
Summary: Used to read or toggle run/walk mode
Description:
Used to read or toggle run/walk mode
Usable: [In Game]
+
 
Summary: Returns the current window size
Description:
me.screensize is a numeric value representing the screen-resolution you playing on.
+
+Possible values are:
+     0 - 640x480
+     2 - 800x600
Usable: [In Game]
+
 
Summary:
Description:
As of 0.41, this is a write only value
Usable: [In Game]
+
 
Summary:
Description:
Removed as of v0.35; conflicts with maphack
Usable: [In Game]
+
 
Summary:
Description:
Removed as of v0.35; conflicts with maphack
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: Returns d2jsp version
Description:
Returns the d2jsp version you are running.
+
+Returns in the MAJOR.MINORSUB format. eg; 0.4138 for 0.41.38
Usable: [In Game] [Out of Game]
+
 
Summary: Returns the title of the Diablo II window
Description:
Returns the title of the Diablo II window that is currently running.
Usable: [In Game] [Out of Game]

Global Functions:

+
 
Summary:
Description:
**NEED DETAILS FILLED IN
Usable: [In Game]
+
 
Summary: Creates a system speaker beep
Description:
Creates a system speaker beep:
+Added beep( [int beepType] )
+
+beepTypes:
+0 = Simple beep. If the sound card is not available, the sound is generated using the speaker.
+1 = MB_ICONASTERISK - SystemAsterisk
+2 = MB_ICONEXCLAMATION - SystemExclamation
+3 = MB_ICONHAND - SystemHand
+4 = MB_ICONQUESTION - SystemQuestion
+5 = MB_OK - SystemDefault
Usable: [In Game] [Out of Game]
+
 
Summary: Blocks or unblocks the event before it hits Diablo II
Description:
blockEvent( EVENT_ID, true/false );
+Blocks the event you request from Diablo II
+Set to true to block, false to unblock
+
+Note: This works in and out of game, and doesnt get reset between games.
+
+Note: Scripts still get the events, so you can script blockers or GUIs relatively easily now.
+
+Valid events: EVENT_MOUSEDOWN, EVENT_MOUSEUP, EVENT_KEYDOWN, EVENT_KEYUP
Usable: [In Game] [Out of Game]
+
 
Summary: Blocks Diablo II from auto minimizing
Description:
Set to 1 or true to block D2 from minimizing when it loses focus. Set to 0 or false to allow D2 to auto minimize.
+
+Note: This will not bring d2 back into focus, if it is out of focus.
Usable: [In Game] [Out of Game]
+
 
Summary: Check if path between two objects is clear. Returns 0 if path is clear, 1 if blocked.
Description:
Used to determine what is at an x,y coordinate or if two units or two x,y coordinates have line of sight to each other. The bitmask determines what kind of line of sight. Most useful is bit 0 for walk and bit 1 for vision.
+
+bit 0 : block walk
+bit 1 : block light + block Line Of Sight (the possibility to see monsters)
+bit 2 : block ranged
+bit 3 : block Player's walk but not Mercenary's walk weird)
+bit 4 : some doors, entry/exits, a few waypoints.
+bit 5 : block light only (not LOS). This is scenery, rocks, trees, etc.
+bit 6 : ?
+bit 7 : Players (yourself and others)
+bit 8 : NPCs & monsters
+bit 9 : Items
+bit 10 : Objects
+bit 11 : Closed doors
+bit 12 : ?
+bit 13 : friendly NPCs
+bit 14 : ?
+bit 15 : dead bodies
Usable: [In Game]
+
 
Summary:
Description:
**NEED DETAILS FILLED IN
Usable: [In Game]
+
 
Summary: Calls click functions inside d2 (not real mouse clicks, but the function called by clicking)
Description:
Calls click functions inside d2 (not real mouse clicks, but the function called by clicking)
+
+clickType = 0 left down, 1 left hold, 2 left up, 3 right down, 4 right hold, 5 right up
+shiftKey = 0 or 1 (shift off or on)
+*This function replaces the following commands: move, useSkill, useSkillAt, interact**
+* The above commands will be deprecated and eventually removed from the core. Please update your scripts
+** interact() will remain for waypoint and grab item to cursor usage and player trade only
+Usage: Try and send down then up commands as much as possible to correctly simulate actual game play. Use "hold" as appropriate.
+Note: Sending Down but not Up will result in a Mouse Down lock that will hinder regular gameplay until the game detects mouse up.
+Be sure and send both down AND up, even if it doesnt seem applicable (it is)
Usable: [In Game]
+
 
Summary: Clicks a Party option
Description:
Clicks a party option:
+
+0 = Loot toggle
+1 = Hostile toggle
+2 = Party with Player
+3 = Leave Party
Usable: [In Game]
+
 
Summary: Copys a unit to another variable
Description:
Copys a unit to another variable
+
+**Note: unit1 = getUnit(0); unit2 = unit1; is NOT valid! You must use unit2 = copyUnit(unit1);
Usable: [In Game]
+
 
Summary: Creates the directory specified
Description:
Creates the directory specified, starting directory is scripts/
+    Returns true/false, true if the directory creation succeeds.
Usable: [In Game] [Out of Game]
+
 
Summary: Delays for a specified time
Description:
Delays for a specified time in milliseconds
Usable: [In Game] [Out of Game]
+
 
Summary: Opens a file for reading/writing
Description:
Open a file for reading/writing:
+
+Int File open modes:
+0 = Read
+1 = Write
+2 = Append
+
+String open modes: (Added in 0.42)
+r, w, a, rb, wb, ab, r+, w+, a+, rb+, wb+, ab+
Usable: [In Game] [Out of Game]
+
 
Summary: Gets an area object
Description:
Gets an area object, areaId is optional, if not passed uses current area. Returns Area object.
+Note: If invalid areaid is passed (wrong act, etc), it will return undefined.
Usable: [In Game]
+
 
Summary: Returns a stat value. basestat is an integer 0-23. Classid is an object classid (an integer). statnum is an integer 0-N. Returns undefined for invalid parameters.
Description:
Basestat numbers are: (see libs/getBaseStat.d2l for an includable list of constants)
+0 - items
+1 - monstats (&npcs)
+2 - skilldesc
+3 - skills
+4 - objects
+5 - missiles
+6 - monstats2
+7 - itemstatcost
+8 - levels
+9 - leveldefs
+10 - lvlmaze
+11 - lvlsub
+12 - lvlwarp
+13 - lvlprest
+14 - lvltypes
+15 - charstats
+16 - setitems
+17 - uniqueitems
+18 - sets
+19 - itemtypes
+20 - runes (v0.44)
+21 - cubemain (v0.44)
+22 - gems (v0.45)
+23 - experience (v0.45)
+24 - pettype (v0.46)
+25 - SuperUniques (v0.50)
+
+See libs/base_*.d2l for all the different statnums. See tools/dbs.d2j for a tool to dump all of these.
Usable: [In Game]
+
 
Summary: Returns the cursor type of your cursor
Description:
Returns the cursor type of your cursor, pass one to see "Shop Mode" cursor types.
+
+Regular Modes: 1 = regular, 3 and 4 = item on cursor, 6 = id scroll, 7 = shop cursor
+
+Shop Mode (7): 1 = regular, 2 = repair, 3 = buy, 4 = sell
Usable: [In Game]
+
 
Summary:
Description:
Pass two unit objects to get the distance between the two.
Usable: [In Game]
+
 
Summary: Returns a localized D2 String
Description:
Returns a localized D2 String (unicode)
+
+Works out of game as of 0.41
Usable: [In Game] [Out of Game]
+
 
Summary: Returns Screen Relative X Y coordinates of mouse cursor
Description:
Returns Screen Relative X Y coordinates of mouse cursor
+
+If paramater is 1, will return Game Relative X Y coordinates of mouse cursor.
+
+The returned value is a 2 member array, containing the X and Y coordinate
Usable: [In Game]
+
 
Summary: Returns current process Id
Description:
Returns the value of the current process id
Usable: [In Game] [Out of Game]
+
 
Summary: Gets a partyplayer
Description:
Gets a partyplayer from a player's global id, pass no param to get your partyplayer object (used to enumerate the rest of the people in the game)
Usable: [In Game]
+
 
Summary: Returns a walkable path from XY to XY
Description:
Returns a FULL PATH of coords from start to finish.
+Note: returns undefined if no path can be built.
+Note: areaId is the Starting area that the x1 and y1 reside in.
+Note: cleanPath is TRUE by default, set to false if you have trouble building a path (ie, Arcane Sanctuary)
+path[index][0] is the X value, path[index][1] is the Y value
+For more info on this, contact me (njaguar) on the forums or IRC.
Usable: [In Game]
+
 
Summary: Returns player's flags
Description:
Returns player's flags, works with players off screen, as long as you know their global Id
+
+Interchange player1 and player2 to find if they are hostile to you and vice versa.
+
+flag: 8 = hostility check, 1 = loot check
Usable: [In Game]
+
 
Summary: Returns an array of objects. Type, classid, and roomarray can be null. If classid is null, returns all preset units of that type in the area. If type is null, returns all preset units of all types in the area.
Description:
A preset unit is a unit that is off screen, and maybe not yet available to getUnit(). Use this to get the x/y coordinates of remote objects such as waypoints, NPCs, objects, items or tiles. The returned object has the following properties:
+presetunit.type
+presetunit.roomx
+presetunit.roomy
+presetunit.x
+presetunit.y
+presetunit.id
+
+
+In order to get actual x/y coordinates, you will need to add 5 * room x/y. See example.
+
+The parameter info is as follows:
+presetunit = getPresetUnits( int area, int type, int classid, roomarray );
+
+area        The area you want query for presetunits, this parameter must be
+        a valid area number of the act you stay in.
+
+type        The type of the presetunits you are looking for. Valid types are:
+        0 is Player
+        1 is Monster/NPC
+        2 is Object
+        3 is Missile
+        4 is Item
+        5 is Tile
+        type may be null, in that case you would get presetunits of any
+        type.
+
+classid        The classid of the presetunits you are looking for. i.e. if you
+        are looking for your stash, the stash is classid 267.
+        classid may be null, in that case you would get presetunits
+        with any classid.
+    
+roomarray    This argument is an array of numbers. Each number represents a room
+        number of specific room (object room, property number).
+        i.e. when you are only interested in presetunits of the rooms 529
+        and 530 so setup an array (myRoomArray = [529, 530];) and pass it
+        as 4th argument.
+        roomarray may be null, in that case you would get presetunits
+        regaedless of the room where they are in.
+
+Result:
+-------
+
+The result is an array of presetunit - objects,
+indexed starting with 0 up to (array.length-1).
+
+So array.length represents the count of matching presetunits.
+
+If there are no presetunits which comply with the arguments, the result is null.
Usable: [In Game]
+
 
Summary: Gets Attack Rating or Block %
Description:
Gets Attack Rating or Block %
+
+** Notes: For value, Pass 0 for right hand, 1 for left hand, this will return Attack Rating %
+
+To get Block %, call it like this: getRating( 3, 0 );
Usable: [In Game]
+
 
Summary: Returns the Repair All cost
Description:
Returns the Repair All cost based upon the given npc
+
+*Note: Will crash if you use an invalid classid, so use 0x9A if you don't have an id.
Usable: [In Game]
+
 
Summary: Gets a Room object
Description:
Gets a room object.
+
+If no params are passed, grabs the first (in memory) room in an area.
+
+If 0 is passed, returns the current room the player is standing in.
+
+If areaId is passed, returns the first room (in memory) of that area
+
+If area, x, and y are passed, returns that specific room.
Usable: [In Game]
+
 
Summary: Gets a screen object
Description:
Gets a screen object that allows you to draw to the screen
+
+**Note: Works out of game as of v0.41
+**As of 0.44:
+Added constructors to getScreenHook();    // see examples as follows, each param is optional
+Base Syntax: getScreenHook( [String text [, int x [, int y [, int x2 [, int y2 [, int color [, int font [, int type [, int opacity]]]]]]]]] );
+Example1: getScreenHook( "hello", 100, 100 );    // sets hello text screenhook to 100,100
+Example2: getScreenHook( "", 50, 50, 75, 75, 0x20, 0, 1 );    // draws a box at 50,50,75,75, of white color and default opacity
+Example3: getScreenHook( "text w/ diff font", 100, 100, -1, -1, 0, 4 );    // uses the #4 font instead of the default
Usable: [In Game] [Out of Game]
+
 
Summary: Gets a script object
Description:
Returns the first script in d2jsp's memory space
+
+As of version 0.46:
+Added new overload to getScript( [1] );    // if you pass 1 (optional), will return the current script
+Useful if you want to send messages to yourself to raise 'custom' events.
Usable: [In Game] [Out of Game]
+
 
Summary: Gets the passed text's width and height
Description:
Returns the width and height for a particular strings font. Useful for building rectangles behind text.
+
+Returns a two dimensional int array, containing the width and height respectively.
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary: Returns the system GetTickCount value.
Description:
Returns the value from GetTickCount()
Usable: [In Game] [Out of Game]
+
 
Summary: Returns information about Player Trading
Description:
Returns various trade informations
+Mode = :
+    0 = Return General Trade Mode, returns: 0 = no trade, 1 = requested trade, 2 = waiting for you to accept trade, 3,5,7=in trade
+    1 = Return Trading Recipients Name (if not in trade, returns last traders name)
+    2 = Return Trading Recipients Global ID (if not in trade, returns last traders id)
Usable: [In Game]
+
 
Summary: Returns UI Mode
Description:
Returns various UI modes, see uiflag.txt for full list
Usable: [In Game]
+
 
Summary: Gets a Unit Object
Description:
Gets a Unit Object:
+
+Type is required
+
+Second parameter can be the Name of the unit, the item code (3 letters), or the classId of the unit.
+
+Third Parameter is the modeId of the unit, can also be a mask, as follows:
+To use this, set the 30th bit to 1, then any other modes' bit index to 1 that you want the core to mask.
+Example to return any dead monster, modes are 0 for death, 12 for dead.
+dead_unit = getUnit(1, null, (1<<29) | (1<<0) | (1<<12));
+** Note: THIS DOES NOT WORK ON ANY MODES GREATER THAN 28! Example: Does NOT work on item modes 100+, or 200+!
+
+Fourth param is the globalId of the unit
+
+**Note: You may pass null the 2nd, 3rd, or 4th parameters to 'skip' them in order to use a later parameter, eg: getUnit(0, null, 1);
+
+For a complete list of modes, see modes.txt
+
+Pass 100 to type to get the unit under the cursor (selected)
+Pass 101 to get the unit you are currently interacted with (shopping)
+Pass 102 to get your mercenary unit. (As of v0.50)
Usable: [In Game]
+
 
Summary: Returns if you have a waypoint or not
Description:
Returns true or false if you have it.
+0 to 8 = act 1,
+9 to 17 = act 2, etc.
Usable: [In Game]
+
 
Summary: Moves/drops gold
Description:
Moves/drops gold
+
+mode 1 = drop, 2 = inventory to trade, 3 = inventory to stash, 4 = stash to inventory
Usable: [In Game]
+
 
Summary: Includes a specified file into the current running script
Description:
Includes the specified filename and parses it into the current running script. All methods and properties defined inside will be available to the main calling script.
+
+**Note: Includes are forced into libs/
Usable: [In Game] [Out of Game]
+
 
Summary: Determines is a file is already included
Description:
Returns true or false, if the fileName passed is included or not
+
+Note: Pass the same fileName you pass to include();
Usable: [In Game] [Out of Game]
+
 
Summary: Loads and runs specified script
Description:
Loads a script from a specified file and runs it under the current scope (in or out of game)
Usable: [In Game] [Out of Game]
+
 
Summary: Plays any game sound
Description:
Plays any sound listed in the sounds.txt table (by id)
+
+**Note: currently plays at the default background noise volume level, volume control will be a later feature
Usable: [In Game]
+
 
Summary:
Description:
print command
Usable: [In Game] [Out of Game]
+
 
Summary: Quits the current game
Description:
Will cause the current game to quit (exit).
Usable: [In Game]
+
 
Summary: Closes Diablo II.exe
Description:
Will attempt to completely close Diablo II (this is NOT a kill process!)
+
+Note: If Diablo II is frozen, or freezes during the quit, the process will still exist in memory.
Usable: [In Game] [Out of Game]
+
 
Summary: Registers your script to receive an event
Description:
Registers your script to receive an event determined by EVENT_ID. See the list of EVENT_* contants for a list of events
+
+Second param is your function that the event will subsequently call when fired.
+
+**Note: Pass 0 as the second parameter to unregister an event.
Usable: [In Game] [Out of Game]
+
 
Summary: Random Number Generator
Description:
Generates a random number between Low and High.
Usable: [In Game] [Out of Game]
+
 
Summary: Run Javascript Garbage Collector
Description:
Use this to force a run of Spidermonkey's garbage collector.
Usable: [In Game] [Out of Game]
+
 
Summary: Sends text to all players.
Description:
Sends text to everyone in a game, instead of a local print.
Usable: [In Game] [Out of Game]
+
 
Summary: Sends a text message to all running scripts
Description:
Sends a text message to all running scripts that is caught by the scriptmsgHandler() event handler
Usable: [In Game] [Out of Game]
+
 
Summary: Sends a WM_COPYDATA message to another window
Description:
This functions sends a WM_COPYDATA event message to another window on your system. It basically is: SendMessage( handle, WM_COPYDATA .. )
+
+Returns true if the command succeeds and the receiving window accepts it. Otherwise returns false.
+
+This is a very advanced feature. The primary reason for adding it was to replace DDE in autod2jsp.
+
+Notes:
+Added a WM_COPYDATA catcher in the core. Will now process WM_COPYDATA messages.
+        Id 1 = Execute as a script, Id 2 = Broadcast as a message to running scripts.
+        lpData must be a pointer to a valid char * to execute or broadcast.
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
**NEED DETAILS FILLED IN
Usable: [In Game] [Out of Game]
+
 
Summary: Plays an emote sound
Description:
Plays the selected sound effect, emulating the numeric pad 0 to 7 keys
+
+**Note: Only values 25 to 32 work. They send the sound for your character:
+25 = Help
+26 = Follow Me
+27 = This Is For You
+28 = Thank You
+29 = Oops
+30 = Goodbye
+31 = Die
+32 = Run
Usable: [In Game]
+
 
Summary: minimizes or restores the d2 window
Description:
Minimizes or restores the d2 window
+Note: Set to true to minimize, false to restore
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary: Stops the script(s)
Description:
Will stop all running scripts under the current game scope if called without params.
+Call with a 1 to terminate only the calling script.
Usable: [In Game] [Out of Game]
+
 
Summary: Submits Item to Drop Boxes
Description:
Submits Item to boxes like Orifice, Add Sockets, Imbue, etc.
+
+**Note: Item must first be on cursor
Usable: [In Game]
+
 
Summary: Takes a screenshot
Description:
Calls the D2 function that takes a screenshot and places the file in your Diablo II/ directory
+
+**Note: Works out of game as of v0.41
Usable: [In Game] [Out of Game]
+
 
Summary: Clicks Cube Transmute Button
Description:
Clicks Cube Transmute Button
Usable: [In Game]
+
 
Summary:
Description:
Uses a skill point on the number value specified by "skillId". Right now, it only accepts a numeric value, see skills.txt
Usable: [In Game]
+
 
Summary:
Description:
Uses a stat point on the value specified by "statId". (see stats.txt)
Usable: [In Game]
+
 
Summary:
Description:
Switches your weapon
+
+If you pass 1, it will return which tab is selected, 0 for 1st, 1 for 2nd
Usable: [In Game]

Global Constants:

+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary: Event for Game Message
Description:
This event is fired when the game give screen message.
+The first parameter passed is the string displayed on the screen
+
+The 2nd param is a value indicating where the message is coming from.
Usable: [In Game] [Out of Game]
+
 
Summary: Event for Player Hostile
Description:
This event is fired when a player goes hostile with you. The parameter passed is the string displayed on the screen. You can get the hostiling player name from this. The 2nd param is the color string, though this will likely be a static color.
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary: Item Stat event
Description:
fires off whenever an item stat changes (eg, quantity)
+Passes three params to the method: itemGID, statno, value
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary: Event for life/mana changes on player
Description:
This event will fire whenever your life or mana changes. Two int params are passed to your event function: life and mana
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: Event for Missile State change
Description:
This event fires whenever a missile state changes.
+Passes three params to the method: gid, stateno, value
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: NPC Stat event
Description:
fires off whenever a monster stat changes
+Passes three params to the method: monsterGID, statno, value
Usable: [In Game]
+
 
Summary: Event for Monster State change
Description:
This event fires whenever a monster or npc state changes.
+Passes three params to the method: gid, stateno, value
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary:
Description:
Usable: [In Game]
+
 
Summary: Player Stat event
Description:
fires off whenever a player stat changes
+Passes three params to the method: playerGID, statno, value
Usable: [In Game]
+
 
Summary: Event for Player State change
Description:
This event fires whenever a player state changes.
+Passes three params to the method: gid, stateno, value
Usable: [In Game]
+
 
Summary: EVENT_QUEST constant
Description:
The constant for the EVENT_QUEST event
Usable: [In Game]
+
 
Summary:
Description:
Usable: [In Game] [Out of Game]
+
 
Summary: EVENT_UNITMOVE constant
Description:
The EVENT_UNITMOVE constant for registerEvent
+
+**Removed in 0.46! Use the individual unit move events
Usable: [In Game]
+
 
Summary: Event when the window loses or gains focus
Description:
This event fires when the D2 window loses or gains focus.
+The value passed is 0 for lost focus or 1 for gained focus
Usable: [In Game] [Out of Game]
\ No newline at end of file diff --git a/d2bs/kolbot/sdk/data/global/excel/states.txt b/d2bs/kolbot/sdk/data/global/excel/states.txt new file mode 100644 index 000000000..f586c897c --- /dev/null +++ b/d2bs/kolbot/sdk/data/global/excel/states.txt @@ -0,0 +1,185 @@ +state id +none 0 +freeze 1 +poison 2 +resistfire 3 +resistcold 4 +resistlight 5 +resistmagic 6 +playerbody 7 +resistall 8 +amplifydamage 9 +frozenarmor 10 +cold 11 +inferno 12 +blaze 13 +bonearmor 14 +concentrate 15 +enchant 16 +innersight 17 +skill_move 18 +weaken 19 +chillingarmor 20 +stunned 21 +spiderlay 22 +dimvision 23 +slowed 24 +fetishaura 25 +shout 26 +taunt 27 +conviction 28 +convicted 29 +energyshield 30 +venomclaws 31 +battleorders 32 +might 33 +prayer 34 +holyfire 35 +thorns 36 +defiance 37 +thunderstorm 38 +lightningbolt 39 +blessedaim 40 +stamina 41 +concentration 42 +holywind 43 +holywindcold 44 +cleansing 45 +holyshock 46 +sanctuary 47 +meditation 48 +fanaticism 49 +redemption 50 +battlecommand 51 +preventheal 52 +conversion 53 +uninterruptable 54 +ironmaiden 55 +terror 56 +attract 57 +lifetap 58 +confuse 59 +decrepify 60 +lowerresist 61 +openwounds 62 +dopplezon 63 +criticalstrike 64 +dodge 65 +avoid 66 +penetrate 67 +evade 68 +pierce 69 +warmth 70 +firemastery 71 +lightningmastery 72 +coldmastery 73 +swordmastery 74 +axemastery 75 +macemastery 76 +polearmmastery 77 +throwingmastery 78 +spearmastery 79 +increasedstamina 80 +ironskin 81 +increasedspeed 82 +naturalresistance 83 +fingermagecurse 84 +nomanaregen 85 +justhit 86 +slowmissiles 87 +shiverarmor 88 +battlecry 89 +blue 90 +red 91 +death_delay 92 +valkyrie 93 +frenzy 94 +berserk 95 +revive 96 +skel_mastery 97 +sourceunit 98 +redeemed 99 +healthpot 100 +holyshield 101 +just_portaled 102 +monfrenzy 103 +corpse_nodraw 104 +alignment 105 +manapot 106 +shatter 107 +sync_warped 108 +conversion_save 109 +pregnant 110 +golem_mastery 111 +rabies 112 +defense_curse 113 +blood_mana 114 +burning 115 +dragonflight 116 +maul 117 +corpse_noselect 118 +shadowwarrior 119 +feralrage 120 +skilldelay 121 +progressive_damage 122 +progressive_steal 123 +progressive_other 124 +progressive_fire 125 +progressive_cold 126 +progressive_lightning 127 +shrine_armor 128 +shrine_combat 129 +shrine_resist_lightning 130 +shrine_resist_fire 131 +shrine_resist_cold 132 +shrine_resist_poison 133 +shrine_skill 134 +shrine_mana_regen 135 +shrine_stamina 136 +shrine_experience 137 +fenris_rage 138 +wolf 139 +bear 140 +bloodlust 141 +changeclass 142 +attached 143 +hurricane 144 +armageddon 145 +invis 146 +barbs 147 +wolverine 148 +oaksage 149 +vine_beast 150 +cyclonearmor 151 +clawmastery 152 +cloak_of_shadows 153 +recycled 154 +weaponblock 155 +cloaked 156 +quickness 157 +bladeshield 158 +fade 159 +summonresist 160 +oaksagecontrol 161 +wolverinecontrol 162 +barbscontrol 163 +debugcontrol 164 +itemset1 165 +itemset2 166 +itemset3 167 +itemset4 168 +itemset5 169 +itemset6 170 +runeword 171 +restinpeace 172 +corpseexp 173 +whirlwind 174 +fullsetgeneric 175 +monsterset 176 +delerium 177 +antidote 178 +thawing 179 +staminapot 180 +passive_resistfire 181 +passive_resistcold 182 +passive_resistltng 183 diff --git a/d2bs/kolbot/sdk/enchants.txt b/d2bs/kolbot/sdk/enchants.txt new file mode 100644 index 000000000..130068d8e --- /dev/null +++ b/d2bs/kolbot/sdk/enchants.txt @@ -0,0 +1,18 @@ + {"Extra Strong Desc", 0, &aszEnchantDescs[5], 0, 1}, + {"Extra Fast Desc", 0, &aszEnchantDescs[6], 0, 1}, + {"Cursed Desc", 0, &aszEnchantDescs[7], 0, 1}, + {"Magic Resistant Desc", 0, &aszEnchantDescs[8], 0, 1}, + {"Fire Enchanted Desc", 0, &aszEnchantDescs[9], 0, 1}, + {"Champion Desc", 0, &aszEnchantDescs[16], 0, 1}, + {"Lightning Enchanted Desc", 0, &aszEnchantDescs[17], 0, 1}, + {"Cold Enchanted Desc", 0, &aszEnchantDescs[18], 0, 1}, + {"Thief Desc", 0, &aszEnchantDescs[24], 0, 1}, + {"Mana Burn Desc", 0, &aszEnchantDescs[25], 0, 1}, + {"Teleportation Desc", 0, &aszEnchantDescs[26], 0, 1}, + {"Spectral Hit Desc", 0, &aszEnchantDescs[27], 0, 1}, + {"Stone Skin Desc", 0, &aszEnchantDescs[28], 0, 1}, + {"Multiple Shots Desc", 0, &aszEnchantDescs[29], 0, 1}, + {"Ghostly Desc", 0, &aszEnchantDescs[36], 0, 1}, + {"Fanatic Desc", 0, &aszEnchantDescs[37], 0, 1}, + {"Possessed Desc", 0, &aszEnchantDescs[38], 0, 1}, + {"Berserker Desc", 0, &aszEnchantDescs[39], 0, 1}, diff --git a/d2bs/kolbot/sdk/getskillinfo.txt b/d2bs/kolbot/sdk/getskillinfo.txt new file mode 100644 index 000000000..039a85d06 --- /dev/null +++ b/d2bs/kolbot/sdk/getskillinfo.txt @@ -0,0 +1,106 @@ +Usage: +returnvar = getSkillInfo([SkillID or SkillName], index); + +0 Id +1 Name +2 ClassID +3 Monster +4 Enhanceable +5 CostMult +6 CostAdd +7 ClassReq +8 AttackRank +9 ItemClass1 String +10 ItemClass2 String +11 ItemClass3 String +12 ItemClass4 String +13 ItemClass5 String +14 ItemClass6 String +15 Anim String +16 MonAnim String +17 AnimID +18 MonAnimID +19 SeqNum +20 Durability +21 Shiver +22 unused +23 UseAttackRate +24 LineOfSight +25 ItemEffect +26 TargetableOnly +27 SearchEnemyXY +28 SearchMonsterNear +29 SelectDead +30 SearchOpenXY +31 TargetPet +32 TargetAlly +33 Range String +34 RangeID +35 AttackNoMana +36 ReqLevel +37 ReqStr +38 ReqDex +39 ReqInt +40 ReqVit +41 ReqSkillId1 +42 ReqSkillId2 +43 ReqSkillId3 +44 CasterState +45 unknown, always -1 +46 IsAura +47 pReqSkill1 ptr +48 pReqSkill2 ptr +49 pReqSkill3 ptr +50 State1 +51 State2 +52 State3 +53 Delay +54 SkillPage +55 SkillRow +56 SkillColumn +57 IconCell +58 LeftSkill +59 ManaShift +60 Mana +61 LvlMana +62 Interrupt +63 InTown +64 Periodic +65 Finishing +66 Passive +67 Param1 +68 Param2 +69 Param3 +70 Param4 +71 Param5 +72 Param6 +73 InGame +74 Open +75 Beta +76 unknown +77 unknown +78 unused +79 ToHit +80 LevToHit +81 HitShift +82 SrcDam +83 unused +84 unused +85 MinDam +86 MaxDam +87 LevDam1 +88 LevDam2 +89 LevDam3 +90 EType +91 EMin +92 EMax +93 ELev1 +94 ELev2 +95 ELev3 +96 ELen +97 ELevLen1 +98 ELevLen2 +99 ELevLen3 +100 Proper Skill Name (Locale based) +101 Item Description (Locale based) + diff --git a/d2bs/kolbot/sdk/itemflags.txt b/d2bs/kolbot/sdk/itemflags.txt new file mode 100644 index 000000000..c2a0101d8 --- /dev/null +++ b/d2bs/kolbot/sdk/itemflags.txt @@ -0,0 +1,21 @@ +Item Flags, pass the 0x hex code to the getFlag(), eg; flag = getFlag(0x400000); + +0x4000000 isRuneword set if it is a runeword (note that 'ith' qualifies ;) +0x1000000 isNamed has a custom name "Player's item" +0x800000 ? was set for all items tested (tested in inv, stash, store) +0x400000 isEthereal 0 if not ethereal +0x200000 isRuneOrPot rune or potion, also set for mephisto's soulstone +0x20000 isStartItem an item that a new character starts with (like javelin and buckler, and the minor healings at the start) +0x10000 isEar a player ear +0x4000 isNotInSocket 0 if in socket, 0 if in belt, 0 if equipped or equipped by merc, 0 for gems/charms/.. +0x2000 isInStore in trade or gamble screen +0x800 isSocketed the item has sockets (they can be full or empty) +0x400 isRejuv only seen set for full rejuvs for now +0x100 isBroken just a bet, but i'm pretty sure it's correct +0x80 isSwitchOut a weapon switch command was performed, and this item is no longer being used +0x40 isSwitchIn a weapon switch command was performed, and this item is now being used +0x10 isIdentified 0 if unid +0x8 isInSocket 8 if in socket, valid for rune and jewels, not gems +0x1 isEquipped player or merc is wearing the item (don't trust too much, especially when bit 9 is set) + +**thanks to bluemind for testing and creating this wonderful list! \ No newline at end of file diff --git a/d2bs/kolbot/sdk/miscscreenmodes.txt b/d2bs/kolbot/sdk/miscscreenmodes.txt new file mode 100644 index 000000000..d16949098 --- /dev/null +++ b/d2bs/kolbot/sdk/miscscreenmodes.txt @@ -0,0 +1,10 @@ +miscscreenmodes.txt: + +1 npc trade open +2 buy cursor +3 sell cursor +4 repair cursor +5 sell/buy confirm +10 trade confirm +11 trade screen +12 Stash Open diff --git a/d2bs/kolbot/sdk/modes.txt b/d2bs/kolbot/sdk/modes.txt new file mode 100644 index 000000000..6766f6145 --- /dev/null +++ b/d2bs/kolbot/sdk/modes.txt @@ -0,0 +1,60 @@ +// ///////////////////////////////////////////////////////////////////////// +// ///////////////////////////////////////////////////////////////////////// +// Mode Flag To Mode List by TDW +// ///////////////////////////////////////////////////////////////////////// +Player Mode Flags: +0x00000001 = 0 = Player death = Player death +0x00000002 = 1 = Player standing outside town = Player standing outside town +0x00000004 = 2 = Player walking = Player walking +0x00000008 = 3 = Player running = Player running +0x00000010 = 4 = Player getting hit = Player getting hit +0x00000020 = 5 = Player standing in town = Player standing in town +0x00000040 = 6 = Player walking in town = Player walking in town +0x00000080 = 7 = Player attacking 1 = Player attacking 1 +0x00000100 = 8 = Player attacking 2 = Player attacking 2 +0x00000200 = 9 = Player blocking = Player blocking +0x00000400 = 10 = Player casting spell skill = Player casting spell skill +0x00000800 = 11 = Player throwing an item = Player throwing an item +0x00001000 = 12 = Player kicking = Player kicking +0x00002000 = 13 = Player using skill 1 = Player using skill 1 +0x00004000 = 14 = Player using skill 2 = Player using skill 2 +0x00008000 = 15 = Player using skill 3 = Player using skill 3 +0x00010000 = 16 = Player using skill 4 = Player using skill 4 +0x00020000 = 17 = Player dead = Player dead +0x00040000 = 18 = Player sequence = Player sequence +0x00080000 = 19 = Player being knocked back = Player being knocked back +NPC Mode Flags: +0x00000001 = 0 = NPC death = NPC death +0x00000002 = 1 = NPC standing still = NPC standing still +0x00000004 = 2 = NPC walking = NPC walking +0x00000008 = 3 = NPC getting hit = NPC getting hit +0x00000010 = 4 = NPC attacking 1 = NPC attacking 1 +0x00000020 = 5 = NPC attacking 2 = NPC attacking 2 +0x00000040 = 6 = NPC blocking = NPC blocking +0x00000080 = 7 = NPC casting spell skill = NPC casting spell skill +0x00000100 = 8 = NPC using skill 1 = NPC using skill 1 +0x00000200 = 9 = NPC using skill 2 = NPC using skill 2 +0x00000400 = 10 = NPC using skill 3 = NPC using skill 3 +0x00000800 = 11 = NPC using skill 4 = NPC using skill 4 +0x00001000 = 12 = NPC dead = NPC dead +0x00002000 = 13 = NPC being knocked back = NPC being knocked back +0x00004000 = 14 = NPC sequence = NPC sequence +0x00008000 = 15 = NPC running = NPC running +Object Mode Flags: +0x00000001 = 0 = Object idle = Object idle +0x00000002 = 1 = Object operating = Object operating +0x00000004 = 2 = Object opened = Object opened +0x00000008 = 3 = Object special 1 = Object special 1 +0x00000010 = 4 = Object special 2 = Object special 2 +0x00000020 = 5 = Object special 3 = Object special 3 +0x00000040 = 6 = Object special 4 = Object special 4 +0x00000080 = 7 = Object special 5 = Object special 5 +Item Mode Flags: +0x00000001 = 0 = Item inven stash cube store = Item inven stash cube store +0x00000002 = 1 = Item equipped self or merc = Item equipped self or merc +0x00000004 = 2 = Item in belt = Item in belt +0x00000008 = 3 = Item on ground = Item on ground +0x00000010 = 4 = Item on cursor = Item on cursor +0x00000020 = 5 = Item being dropped = Item being dropped +0x00000040 = 6 = Item socketed in item = Item socketed in item +// ///////////////////////////////////////////////////////////////////////// diff --git a/d2bs/kolbot/sdk/monster classID's.txt b/d2bs/kolbot/sdk/monster classID's.txt new file mode 100644 index 000000000..5538b2836 --- /dev/null +++ b/d2bs/kolbot/sdk/monster classID's.txt @@ -0,0 +1,706 @@ +Id hcIdx BaseId NextInClass TransLvl NameStr +skeleton1 0 skeleton1 skeleton2 0 Skeleton +skeleton2 1 skeleton1 skeleton3 1 Returned +skeleton3 2 skeleton1 skeleton4 2 BoneWarrior +skeleton4 3 skeleton1 skeleton5 3 BurningDead +skeleton5 4 skeleton1 skeleton6 4 Horror +zombie1 5 zombie1 zombie2 0 Zombie +zombie2 6 zombie1 zombie3 1 HungryDead +zombie3 7 zombie1 zombie4 2 Ghoul +zombie4 8 zombie1 zombie5 3 DrownedCarcass +zombie5 9 zombie1 4 PlagueBearer +bighead1 10 bighead1 bighead2 0 Afflicted +bighead2 11 bighead1 bighead3 1 Tainted +bighead3 12 bighead1 bighead4 2 Misshapen +bighead4 13 bighead1 bighead5 3 Disfigured +bighead5 14 bighead1 bighead6 4 Damned +foulcrow1 15 foulcrow1 foulcrow2 0 FoulCrow +foulcrow2 16 foulcrow1 foulcrow3 1 BloodHawk +foulcrow3 17 foulcrow1 foulcrow4 2 BlackRaptor +foulcrow4 18 foulcrow1 foulcrow5 3 CloudStalker +fallen1 19 fallen1 fallen2 0 Fallen +fallen2 20 fallen1 fallen3 1 Carver +fallen3 21 fallen1 fallen4 2 Devilkin +fallen4 22 fallen1 fallen5 3 DarkOne +fallen5 23 fallen1 fallen6 4 WarpedFallen +brute2 24 brute2 brute3 0 Brute +brute3 25 brute2 brute4 1 Yeti +brute4 26 brute2 brute5 2 Crusher +brute5 27 brute2 brute1 3 WailingBeast +brute1 28 brute2 4 GargantuanBeast +sandraider1 29 sandraider1 sandraider2 0 SandRaider +sandraider2 30 sandraider1 sandraider3 1 Marauder +sandraider3 31 sandraider1 sandraider4 2 Invader +sandraider4 32 sandraider1 sandraider5 3 Infidel +sandraider5 33 sandraider1 sandraider6 4 Assailant +gorgon1 34 gorgon1 gorgon2 0 unused +gorgon2 35 gorgon1 gorgon3 1 unused +gorgon3 36 gorgon1 gorgon4 2 unused +gorgon4 37 gorgon1 3 unused +wraith1 38 wraith1 wraith2 0 Ghost +wraith2 39 wraith1 wraith3 1 Wraith +wraith3 40 wraith1 wraith4 2 Specter +wraith4 41 wraith1 wraith5 3 Apparition +wraith5 42 wraith1 wraith6 4 DarkShape +corruptrogue1 43 corruptrogue1 corruptrogue2 0 DarkHunter +corruptrogue2 44 corruptrogue1 corruptrogue3 1 VileHunter +corruptrogue3 45 corruptrogue1 corruptrogue4 2 DarkStalker +corruptrogue4 46 corruptrogue1 corruptrogue5 3 BlackRogue +corruptrogue5 47 corruptrogue1 4 FleshHunter +baboon1 48 baboon1 baboon2 0 DuneBeast +baboon2 49 baboon1 baboon3 1 RockDweller +baboon3 50 baboon1 baboon4 2 JungleHunter +baboon4 51 baboon1 baboon5 3 DoomApe +baboon5 52 baboon1 baboon7 4 TempleGuard +goatman1 53 goatman1 goatman2 0 MoonClan +goatman2 54 goatman1 goatman3 1 NightClan +goatman3 55 goatman1 goatman4 2 BloodClan +goatman4 56 goatman1 goatman5 3 HellClan +goatman5 57 goatman1 goatman6 4 DeathClan +fallenshaman1 58 fallenshaman1 fallenshaman2 0 FallenShaman +fallenshaman2 59 fallenshaman1 fallenshaman3 1 CarverShaman +fallenshaman3 60 fallenshaman1 fallenshaman4 2 DevilkinShaman +fallenshaman4 61 fallenshaman1 fallenshaman5 3 DarkShaman +fallenshaman5 62 fallenshaman1 fallenshaman6 4 WarpedShaman +quillrat1 63 quillrat1 quillrat2 0 QuillRat +quillrat2 64 quillrat1 quillrat3 1 SpikeFiend +quillrat3 65 quillrat1 quillrat4 2 ThornBeast +quillrat4 66 quillrat1 quillrat5 3 RazorSpine +quillrat5 67 quillrat1 quillrat6 4 JungleUrchin +sandmaggot1 68 sandmaggot1 sandmaggot2 0 SandMaggot +sandmaggot2 69 sandmaggot1 sandmaggot3 1 RockWorm +sandmaggot3 70 sandmaggot1 sandmaggot4 2 Devourer +sandmaggot4 71 sandmaggot1 sandmaggot5 3 GiantLamprey +sandmaggot5 72 sandmaggot1 sandmaggot6 4 WorldKiller +clawviper1 73 clawviper1 clawviper2 0 TombViper +clawviper2 74 clawviper1 clawviper3 1 ClawViper +clawviper3 75 clawviper1 clawviper4 2 Salamander +clawviper4 76 clawviper1 clawviper5 3 PitViper +clawviper5 77 clawviper1 clawviper6 4 SerpentMagus +sandleaper1 78 sandleaper1 sandleaper2 0 SandLeaper +sandleaper2 79 sandleaper1 sandleaper3 1 CaveLeaper +sandleaper3 80 sandleaper1 sandleaper4 2 TombCreeper +sandleaper4 81 sandleaper1 sandleaper5 3 TreeLurker +sandleaper5 82 sandleaper1 sandleaper6 4 RazorPitDemon +pantherwoman1 83 pantherwoman1 pantherwoman2 0 Huntress +pantherwoman2 84 pantherwoman1 pantherwoman3 1 SaberCat +pantherwoman3 85 pantherwoman1 pantherwoman4 2 NightTiger +pantherwoman4 86 pantherwoman1 pantherwoman5 3 HellCat +swarm1 87 swarm1 swarm2 0 Itchies +swarm2 88 swarm1 swarm3 1 BlackLocusts +swarm3 89 swarm1 swarm4 2 PlagueBugs +swarm4 90 swarm1 3 HellSwarm +scarab1 91 scarab1 scarab2 0 DungSoldier +scarab2 92 scarab1 scarab3 1 SandWarrior +scarab3 93 scarab1 scarab4 2 Scarab +scarab4 94 scarab1 scarab5 3 SteelWeevil +scarab5 95 scarab1 scarab6 4 AlbinoRoach +mummy1 96 mummy1 mummy2 0 DriedCorpse +mummy2 97 mummy1 mummy3 1 Decayed +mummy3 98 mummy1 mummy4 2 Embalmed +mummy4 99 mummy1 mummy5 3 PreservedDead +mummy5 100 mummy1 mummy6 4 Cadaver +unraveler1 101 unraveler1 unraveler2 0 HollowOne +unraveler2 102 unraveler1 unraveler3 1 Guardian +unraveler3 103 unraveler1 unraveler4 2 Unraveler +unraveler4 104 unraveler1 unraveler5 3 Horadrim Ancient +unraveler5 105 unraveler1 unraveler6 4 Baal Subject Mummy +chaoshorde1 106 chaoshorde1 chaoshorde2 0 unused +chaoshorde2 107 chaoshorde1 chaoshorde3 1 unused +chaoshorde3 108 chaoshorde1 chaoshorde4 2 unused +chaoshorde4 109 chaoshorde1 a 3 unused +vulture1 110 vulture1 vulture2 0 CarrionBird +vulture2 111 vulture1 vulture3 1 UndeadScavenger +vulture3 112 vulture1 vulture4 2 HellBuzzard +vulture4 113 vulture1 vulture5 3 WingedNightmare +mosquito1 114 mosquito1 mosquito2 0 Sucker +mosquito2 115 mosquito1 mosquito3 1 Feeder +mosquito3 116 mosquito1 mosquito4 2 BloodHook +mosquito4 117 mosquito1 3 BloodWing +willowisp1 118 willowisp1 willowisp2 0 Gloam +willowisp2 119 willowisp1 willowisp3 1 SwampGhost +willowisp3 120 willowisp1 willowisp4 2 BurningSoul +willowisp4 121 willowisp1 willowisp5 3 BlackSoul +arach1 122 arach1 arach2 0 Arach +arach2 123 arach1 arach3 1 SandFisher +arach3 124 arach1 arach4 2 PoisonSpinner +arach4 125 arach1 arach5 3 FlameSpider +arach5 126 arach1 arach6 4 SpiderMagus +thornhulk1 127 thornhulk1 thornhulk2 0 ThornedHulk +thornhulk2 128 thornhulk1 thornhulk3 1 BrambleHulk +thornhulk3 129 thornhulk1 thornhulk4 2 Thrasher +thornhulk4 130 thornhulk1 thornhulk5 3 Spikefist +vampire1 131 vampire1 vampire2 0 GhoulLord +vampire2 132 vampire1 vampire3 1 NightLord +vampire3 133 vampire1 vampire4 2 DarkLord +vampire4 134 vampire1 vampire5 3 BloodLord +vampire5 135 vampire1 vampire6 4 Banished +batdemon1 136 batdemon1 batdemon2 0 DesertWing +batdemon2 137 batdemon1 batdemon3 1 Fiend +batdemon3 138 batdemon1 batdemon4 2 Gloombat +batdemon4 139 batdemon1 batdemon5 3 BloodDiver +batdemon5 140 batdemon1 batdemon6 4 DarkFamiliar +fetish1 141 fetish1 fetish2 0 RatMan +fetish2 142 fetish1 fetish3 1 Fetish +fetish3 143 fetish1 fetish4 2 Flayer +fetish4 144 fetish1 fetish5 3 SoulKiller +fetish5 145 fetish1 fetish6 4 StygianDoll +cain1 146 cain1 0 DeckardCain +gheed 147 gheed 0 Gheed +akara 148 akara 0 Akara +chicken 149 chicken 0 dummy +kashya 150 kashya 0 Kashya +rat 151 rat 0 dummy +rogue1 152 rogue1 0 Dummy +hellmeteor 153 hellmeteor 0 Dummy +charsi 154 charsi 0 Charsi +warriv1 155 warriv1 0 Warriv +andariel 156 andariel 0 Andariel +bird1 157 bird1 0 dummy +bird2 158 bird2 0 dummy +bat 159 bat 0 dummy +cr_archer1 160 cr_archer1 cr_archer2 0 DarkRanger +cr_archer2 161 cr_archer1 cr_archer3 1 VileArcher +cr_archer3 162 cr_archer1 cr_archer4 2 DarkArcher +cr_archer4 163 cr_archer1 cr_archer5 3 BlackArcher +cr_archer5 164 cr_archer1 cr_archer6 4 FleshArcher +cr_lancer1 165 cr_lancer1 cr_lancer2 0 DarkSpearwoman +cr_lancer2 166 cr_lancer1 cr_lancer3 1 VileLancer +cr_lancer3 167 cr_lancer1 cr_lancer4 2 DarkLancer +cr_lancer4 168 cr_lancer1 cr_lancer5 3 BlackLancer +cr_lancer5 169 cr_lancer1 cr_lancer6 4 FleshLancer +sk_archer1 170 sk_archer1 sk_archer2 0 SkeletonArcher +sk_archer2 171 sk_archer1 sk_archer3 1 ReturnedArcher +sk_archer3 172 sk_archer1 sk_archer4 2 BoneArcher +sk_archer4 173 sk_archer1 sk_archer5 3 BurningDeadArcher +sk_archer5 174 sk_archer1 sk_archer6 4 HorrorArcher +warriv2 175 warriv2 0 Warriv +atma 176 atma 0 Atma +drognan 177 drognan 0 Drognan +fara 178 fara 0 Fara +cow 179 cow 0 dummy +maggotbaby1 180 maggotbaby1 maggotbaby2 0 SandMaggotYoung +maggotbaby2 181 maggotbaby1 maggotbaby3 1 RockWormYoung +maggotbaby3 182 maggotbaby1 maggotbaby4 2 DevourerYoung +maggotbaby4 183 maggotbaby1 maggotbaby5 3 GiantLampreyYoung +maggotbaby5 184 maggotbaby1 maggotbaby6 4 WorldKillerYoung +camel 185 camel 0 dummy +blunderbore1 186 blunderbore1 blunderbore2 0 Blunderbore +blunderbore2 187 blunderbore1 blunderbore3 1 Gorbelly +blunderbore3 188 blunderbore1 blunderbore4 2 Mauler +blunderbore4 189 blunderbore1 blunderbore5 3 Urdar +maggotegg1 190 maggotegg1 maggotegg2 0 SandMaggotEgg +maggotegg2 191 maggotegg1 maggotegg3 1 RockWormEgg +maggotegg3 192 maggotegg1 maggotegg4 2 DevourerEgg +maggotegg4 193 maggotegg1 maggotegg5 3 GiantLampreyEgg +maggotegg5 194 maggotegg1 maggotegg6 4 WorldKillerEgg +act2male 195 act2male 0 dummy +act2female 196 act2female 0 Dummy +act2child 197 act2child 0 dummy +greiz 198 greiz 0 Greiz +elzix 199 elzix 0 Elzix +geglash 200 geglash 0 Geglash +jerhyn 201 jerhyn 0 Jerhyn +lysander 202 lysander 0 Lysander +act2guard1 203 act2guard1 0 Dummy +act2vendor1 204 act2vendor1 0 dummy +act2vendor2 205 act2vendor2 0 dummy +crownest1 206 crownest1 crownest2 0 FoulCrowNest +crownest2 207 crownest1 crownest3 1 BloodHawkNest +crownest3 208 crownest1 crownest4 2 BlackVultureNest +crownest4 209 crownest1 3 CloudStalkerNest +meshif1 210 meshif1 0 Meshif +duriel 211 duriel 0 Duriel +bonefetish1 212 bonefetish1 bonefetish2 0 Undead RatMan +bonefetish2 213 bonefetish1 bonefetish3 1 Undead Fetish +bonefetish3 214 bonefetish1 bonefetish4 2 Undead Flayer +bonefetish4 215 bonefetish1 bonefetish5 3 Undead SoulKiller +bonefetish5 216 bonefetish1 bonefetish6 4 Undead StygianDoll +darkguard1 217 darkguard1 darkguard2 0 unused +darkguard2 218 darkguard1 darkguard3 1 unused +darkguard3 219 darkguard1 darkguard4 2 unused +darkguard4 220 darkguard1 darkguard5 3 unused +darkguard5 221 darkguard1 4 unused +bloodmage1 222 bloodmage1 bloodmage2 0 unused +bloodmage2 223 bloodmage1 bloodmage3 1 unused +bloodmage3 224 bloodmage1 bloodmage4 2 unused +bloodmage4 225 bloodmage1 bloodmage5 3 unused +bloodmage5 226 bloodmage1 4 unused +maggot 227 maggot 0 Maggot +sarcophagus 228 sarcophagus 0 MummyGenerator +radament 229 radament 0 Radament +firebeast 230 firebeast 0 unused +iceglobe 231 iceglobe 0 unused +lightningbeast 232 lightningbeast 0 unused +poisonorb 233 poisonorb 0 unused +flyingscimitar 234 flyingscimitar 0 FlyingScimitar +zealot1 235 zealot1 zealot2 0 Zakarumite +zealot2 236 zealot1 zealot3 1 Faithful +zealot3 237 zealot1 zealot4 2 Zealot +cantor1 238 cantor1 cantor2 0 Sexton +cantor2 239 cantor1 cantor3 1 Cantor +cantor3 240 cantor1 cantor4 2 Heirophant +cantor4 241 cantor1 cantor5 3 Heirophant +mephisto 242 mephisto 0 Mephisto +diablo 243 diablo 0 Diablo +cain2 244 cain2 0 DeckardCain +cain3 245 cain3 0 DeckardCain +cain4 246 cain4 0 DeckardCain +frogdemon1 247 frogdemon1 frogdemon2 0 Swamp Dweller +frogdemon2 248 frogdemon1 frogdemon3 1 Bog Creature +frogdemon3 249 frogdemon1 2 Slime Prince +summoner 250 summoner 0 Summoner +tyrael1 251 tyrael1 0 tyrael +asheara 252 asheara 0 asheara +hratli 253 hratli 0 hratli +alkor 254 alkor 0 alkor +ormus 255 ormus 0 ormus +izual 256 izual 0 izual +halbu 257 halbu 0 halbu +tentacle1 258 tentacle1 tentacle2 0 WaterWatcherLimb +tentacle2 259 tentacle1 tentacle3 1 RiverStalkerLimb +tentacle3 260 tentacle1 2 StygianWatcherLimb +tentaclehead1 261 tentaclehead1 tentaclehead2 0 WaterWatcherHead +tentaclehead2 262 tentaclehead1 tentaclehead3 1 RiverStalkerHead +tentaclehead3 263 tentaclehead1 2 StygianWatcherHead +meshif2 264 meshif2 0 meshif +cain5 265 cain5 0 DeckardCain +navi 266 navi 0 navi +bloodraven 267 bloodraven 0 Bloodraven +bug 268 bug 0 Dummy +scorpion 269 scorpion 0 Dummy +rogue2 270 rogue2 0 RogueScout +roguehire 271 roguehire 0 Dummy +rogue3 272 rogue3 0 Dummy +gargoyletrap 273 gargoyletrap 0 GargoyleTrap +skmage_pois1 274 skmage_pois1 skmage_pois2 1 ReturnedMage +skmage_pois2 275 skmage_pois1 skmage_pois3 2 BoneMage +skmage_pois3 276 skmage_pois1 skmage_pois4 3 BurningDeadMage +skmage_pois4 277 skmage_pois1 skmage_pois5 4 HorrorMage +fetishshaman1 278 fetishshaman1 fetishshaman2 0 RatManShaman +fetishshaman2 279 fetishshaman1 fetishshaman3 1 FetishShaman +fetishshaman3 280 fetishshaman1 fetishshaman4 2 FlayerShaman +fetishshaman4 281 fetishshaman1 fetishshaman5 3 SoulKillerShaman +fetishshaman5 282 fetishshaman1 fetishshaman6 4 StygianDollShaman +larva 283 larva 0 larva +maggotqueen1 284 maggotqueen1 maggotqueen2 0 SandMaggotQueen +maggotqueen2 285 maggotqueen1 maggotqueen3 1 RockWormQueen +maggotqueen3 286 maggotqueen1 maggotqueen4 2 DevourerQueen +maggotqueen4 287 maggotqueen1 maggotqueen5 3 GiantLampreyQueen +maggotqueen5 288 maggotqueen1 4 WorldKillerQueen +claygolem 289 claygolem 0 ClayGolem +bloodgolem 290 bloodgolem 0 BloodGolem +irongolem 291 irongolem 0 IronGolem +firegolem 292 firegolem 0 FireGolem +familiar 293 familiar 0 Dummy +act3male 294 act3male 0 Dummy +baboon6 295 baboon6 0 NightMarauder +act3female 296 act3female 0 Dummy +natalya 297 natalya 0 Natalya +vilemother1 298 vilemother1 vilemother2 0 FleshSpawner +vilemother2 299 vilemother1 vilemother3 1 StygianHag +vilemother3 300 vilemother1 vilemother4 2 Grotesque +vilechild1 301 vilechild1 vilechild2 0 FleshBeast +vilechild2 302 vilechild1 vilechild3 1 StygianDog +vilechild3 303 vilechild1 vilechild4 2 GrotesqueWyrm +fingermage1 304 fingermage1 fingermage2 0 Groper +fingermage2 305 fingermage1 fingermage3 1 Strangler +fingermage3 306 fingermage1 fingermage4 2 StormCaster +regurgitator1 307 regurgitator1 regurgitator2 0 Corpulent +regurgitator2 308 regurgitator1 regurgitator3 1 CorpseSpitter +regurgitator3 309 regurgitator1 regurgitator4 2 MawFiend +doomknight1 310 doomknight1 dkfig1 0 DoomKnight +doomknight2 311 doomknight2 0 AbyssKnight +doomknight3 312 doomknight3 dkmag1 0 OblivionKnight +quillbear1 313 quillbear1 quillbear2 0 QuillBear +quillbear2 314 quillbear1 quillbear3 1 SpikeGiant +quillbear3 315 quillbear1 quillbear4 2 ThornBrute +quillbear4 316 quillbear1 quillbear5 3 RazorBeast +quillbear5 317 quillbear1 4 GiantUrchin +snake 318 snake 0 Dummy +parrot 319 parrot 0 Dummy +fish 320 fish 0 Dummy +evilhole1 321 evilhole1 evilhole2 0 Dummy +evilhole2 322 evilhole1 evilhole3 1 Dummy +evilhole3 323 evilhole1 evilhole4 2 Dummy +evilhole4 324 evilhole1 evilhole5 3 Dummy +evilhole5 325 evilhole1 4 Dummy +trap-firebolt 326 trap-firebolt 0 a trap +trap-horzmissile 327 trap-horzmissile 0 a trap +trap-vertmissile 328 trap-vertmissile 0 a trap +trap-poisoncloud 329 trap-poisoncloud 0 a trap +trap-lightning 330 trap-lightning 0 a trap +act2guard2 331 act2guard2 0 Kaelan +invisospawner 332 invisospawner 0 Dummy +diabloclone 333 diablo 0 Diablo +suckernest1 334 suckernest1 suckernest2 0 SuckerNest +suckernest2 335 suckernest1 suckernest3 1 FeederNest +suckernest3 336 suckernest1 suckernest4 2 BloodHookNest +suckernest4 337 suckernest1 3 BloodWingNest +act2hire 338 act2hire 0 Guard +minispider 339 minispider 0 Dummy +boneprison1 340 boneprison1 0 +boneprison2 341 boneprison2 0 +boneprison3 342 boneprison3 0 +boneprison4 343 boneprison4 0 +bonewall 344 bonewall 0 Dummy +councilmember1 345 councilmember1 councilmember2 0 Council Member +councilmember2 346 councilmember1 councilmember3 1 Council Member +councilmember3 347 councilmember1 2 Council Member +turret1 348 turret1 turret2 0 Turret +turret2 349 turret1 turret3 1 Turret +turret3 350 turret1 2 Turret +hydra1 351 hydra1 0 Hydra +hydra2 352 hydra2 0 Hydra +hydra3 353 hydra3 0 Hydra +trap-melee 354 trap-melee 0 a trap +seventombs 355 seventombs 0 Dummy +dopplezon 356 dopplezon 0 Dopplezon +valkyrie 357 valkyrie 0 Valkyrie +act2guard3 358 act2guard3 0 Dummy +act3hire 359 act3hire 0 Iron Wolf +megademon1 360 megademon1 megademon2 0 Balrog +megademon2 361 megademon1 megademon3 1 PitLord +megademon3 362 megademon1 megademon4 2 VenomLord +necroskeleton 363 necroskeleton 0 NecroSkeleton +necromage 364 necromage 0 NecroMage +griswold 365 griswold 0 Griswold +compellingorb 366 compellingorb 0 compellingorb +tyrael2 367 tyrael2 0 tyrael +darkwanderer 368 darkwanderer 0 youngdiablo +trap-nova 369 trap-nova 0 a trap +spiritmummy 370 spiritmummy 0 Dummy +lightningspire 371 lightningspire 0 LightningSpire +firetower 372 firetower 0 FireTower +slinger1 373 slinger1 slinger2 0 Slinger +slinger2 374 slinger1 slinger3 1 SpearCat +slinger3 375 slinger1 slinger4 2 NightSlinger +slinger4 376 slinger1 slinger7 3 HellSlinger +act2guard4 377 act2guard4 0 Dummy +act2guard5 378 act2guard5 0 Dummy +skmage_cold1 379 skmage_cold1 skmage_cold2 1 ReturnedMage +skmage_cold2 380 skmage_cold1 skmage_cold3 2 BoneMage +skmage_cold3 381 skmage_cold1 skmage_cold4 3 BaalColdMage +skmage_cold4 382 skmage_cold1 skmage_cold5 4 HorrorMage +skmage_fire1 383 skmage_fire1 skmage_fire2 1 ReturnedMage +skmage_fire2 384 skmage_fire1 skmage_fire3 2 BoneMage +skmage_fire3 385 skmage_fire1 skmage_fire4 3 BurningDeadMage +skmage_fire4 386 skmage_fire1 skmage_fire5 4 HorrorMage +skmage_ltng1 387 skmage_ltng1 skmage_ltng2 1 ReturnedMage +skmage_ltng2 388 skmage_ltng1 skmage_ltng3 2 BoneMage +skmage_ltng3 389 skmage_ltng1 skmage_ltng4 3 BurningDeadMage +skmage_ltng4 390 skmage_ltng1 skmage_ltng5 4 HorrorMage +hellbovine 391 hellbovine 0 Hell Bovine +window1 392 window1 0 +window2 393 window2 0 +slinger5 394 slinger5 slinger6 0 SpearCat +slinger6 395 slinger5 1 NightSlinger +fetishblow1 396 fetishblow1 fetishblow2 0 RatMan +fetishblow2 397 fetishblow1 fetishblow3 1 Fetish +fetishblow3 398 fetishblow1 fetishblow4 2 Flayer +fetishblow4 399 fetishblow1 fetishblow5 3 SoulKiller +fetishblow5 400 fetishblow1 fetishblow6 4 StygianDoll +mephistospirit 401 mephistospirit 0 Dummy +smith 402 smith 0 The Smith +trappedsoul1 403 trappedsoul1 0 TrappedSoul +trappedsoul2 404 trappedsoul2 0 TrappedSoul +jamella 405 jamella 0 Jamella +izualghost 406 izualghost 0 Izual +fetish11 407 fetish11 0 RatMan +malachai 408 malachai 0 Malachai +hephasto 409 hephasto 0 The Feature Creep +Expansion +wakeofdestruction 410 wakeofdestruction 0 Wake of Destruction +chargeboltsentry 411 chargeboltsentry 0 Charged Bolt Sentry +lightningsentry 412 lightningsentry 0 Lightning Sentry +bladecreeper 413 bladecreeper 0 Blade Creeper +invisopet 414 invisopet 0 Invis Pet +infernosentry 415 infernosentry 0 Inferno Sentry +deathsentry 416 deathsentry 0 Death Sentry +shadowwarrior 417 shadowwarrior 0 Shadow Warrior +shadowmaster 418 shadowmaster 0 Shadow Master +druidhawk 419 druidhawk 0 Druid Hawk +spiritwolf 420 spiritwolf fenris 0 Druid Spirit Wolf +fenris 421 spiritwolf 1 Druid Fenris +spiritofbarbs 422 spiritofbarbs heartofwolverine 0 Spirit of Barbs +heartofwolverine 423 spiritofbarbs oaksage 1 Heart of Wolverine +oaksage 424 spiritofbarbs 2 Oak Sage +plaguepoppy 425 plaguepoppy 0 Druid Plague Poppy +cycleoflife 426 cycleoflife 0 Druid Cycle of Life +vinecreature 427 vinecreature 0 Vine Creature +druidbear 428 druidbear 0 Druid Bear +eagle 429 eagle 0 Eagle +wolf 430 wolf 0 Wolf +bear 431 bear 0 Bear +barricadedoor1 432 barricadedoor1 barricadedoor2 0 Barricade Door +barricadedoor2 433 barricadedoor1 1 Barricade Door +prisondoor 434 prisondoor 0 Prison Door +barricadetower 435 barricadetower 0 Barricade Tower +reanimatedhorde1 436 reanimatedhorde1 reanimatedhorde2 0 RotWalker +reanimatedhorde2 437 reanimatedhorde1 reanimatedhorde3 1 ReanimatedHorde +reanimatedhorde3 438 reanimatedhorde1 reanimatedhorde4 2 ProwlingDead +reanimatedhorde4 439 reanimatedhorde1 reanimatedhorde5 3 UnholyCorpse +reanimatedhorde5 440 reanimatedhorde1 reanimatedhorde6 4 DefiledWarrior +siegebeast1 441 siegebeast1 siegebeast2 0 Siege Beast +siegebeast2 442 siegebeast1 siegebeast3 1 CrushBiest +siegebeast3 443 siegebeast1 siegebeast4 2 BloodBringer +siegebeast4 444 siegebeast1 siegebeast5 3 GoreBearer +siegebeast5 445 siegebeast1 4 DeamonSteed +snowyeti1 446 snowyeti1 snowyeti2 0 SnowYeti1 +snowyeti2 447 snowyeti1 snowyeti3 1 SnowYeti2 +snowyeti3 448 snowyeti1 snowyeti4 2 SnowYeti3 +snowyeti4 449 snowyeti1 3 SnowYeti4 +wolfrider1 450 wolfrider1 wolfrider2 0 WolfRider1 +wolfrider2 451 wolfrider1 wolfrider3 1 WolfRider2 +wolfrider3 452 wolfrider1 2 WolfRider3 +minion1 453 minion1 minion2 0 Minionexp +minion2 454 minion1 minion3 2 Slayerexp +minion3 455 minion1 minion4 1 IceBoar +minion4 456 minion1 minion5 3 FireBoar +minion5 457 minion1 minion6 4 HellSpawn +minion6 458 minion1 minion7 5 IceSpawn +minion7 459 minion1 minion8 6 GreaterHellSpawn +minion8 460 minion1 minion9 7 GreaterIceSpawn +suicideminion1 461 suicideminion1 suicideminion2 0 FanaticMinion +suicideminion2 462 suicideminion1 suicideminion3 1 BerserkSlayer +suicideminion3 463 suicideminion1 suicideminion4 2 ConsumedIceBoar +suicideminion4 464 suicideminion1 suicideminion5 3 ConsumedFireBoar +suicideminion5 465 suicideminion1 suicideminion6 4 FrenziedHellSpawn +suicideminion6 466 suicideminion1 suicideminion7 5 FrenziedIceSpawn +suicideminion7 467 suicideminion1 suicideminion8 6 InsaneHellSpawn +suicideminion8 468 suicideminion1 7 InsaneIceSpawn +succubus1 469 succubus1 succubus2 0 Succubusexp +succubus2 470 succubus1 succubus3 1 VileTemptress +succubus3 471 succubus1 succubus4 2 StygianHarlot +succubus4 472 succubus1 succubus5 3 Hell Temptress +succubus5 473 succubus1 succubus6 4 Blood Temptress +succubuswitch1 474 succubuswitch1 succubuswitch2 0 Dominus +succubuswitch2 475 succubuswitch1 succubuswitch3 1 VileWitch +succubuswitch3 476 succubuswitch1 succubuswitch4 2 StygianFury +succubuswitch4 477 succubuswitch1 succubuswitch5 3 Blood Witch +succubuswitch5 478 succubuswitch1 succubuswitch6 4 Hell Witch +overseer1 479 overseer1 overseer2 0 OverSeer +overseer2 480 overseer1 overseer3 1 Lasher +overseer3 481 overseer1 overseer4 2 OverLord +overseer4 482 overseer1 overseer5 3 BloodBoss +overseer5 483 overseer1 4 HellWhip +minionspawner1 484 minionspawner1 minionspawner2 0 MinionSpawner +minionspawner2 485 minionspawner1 minionspawner3 1 MinionSlayerSpawner +minionspawner3 486 minionspawner1 minionspawner4 2 MinionIce/fireBoarSpawner +minionspawner4 487 minionspawner1 minionspawner5 3 MinionIce/fireBoarSpawner +minionspawner5 488 minionspawner1 minionspawner6 4 Minionice/hellSpawnSpawner +minionspawner6 489 minionspawner1 minionspawner7 5 MinionIce/fireBoarSpawner +minionspawner7 490 minionspawner1 minionspawner8 6 MinionIce/fireBoarSpawner +minionspawner8 491 minionspawner1 7 Minionice/hellSpawnSpawner +imp1 492 imp1 imp2 0 Imp1 +imp2 493 imp1 imp3 1 Imp2 +imp3 494 imp1 imp4 2 Imp3 +imp4 495 imp1 imp5 3 Imp4 +imp5 496 imp1 imp6 4 Imp5 +catapult1 497 catapult1 catapult2 0 CatapultS +catapult2 498 catapult1 catapult3 1 CatapultE +catapult3 499 catapult1 catapult4 2 CatapultSiege +catapult4 500 catapult1 3 CatapultW +frozenhorror1 501 frozenhorror1 frozenhorror2 0 Frozen Horror1 +frozenhorror2 502 frozenhorror1 frozenhorror3 1 Frozen Horror2 +frozenhorror3 503 frozenhorror1 frozenhorror4 2 Frozen Horror3 +frozenhorror4 504 frozenhorror1 frozenhorror5 3 Frozen Horror4 +frozenhorror5 505 frozenhorror1 4 Frozen Horror5 +bloodlord1 506 bloodlord1 bloodlord2 0 Blood Lord1 +bloodlord2 507 bloodlord1 bloodlord3 1 Blood Lord2 +bloodlord3 508 bloodlord1 bloodlord4 2 Blood Lord3 +bloodlord4 509 bloodlord1 bloodlord5 3 Blood Lord4 +bloodlord5 510 bloodlord1 bloodlord6 4 Blood Lord5 +larzuk 511 larzuk 0 Larzuk +drehya 512 drehya 0 Drehya +malah 513 malah 0 Malah +nihlathak 514 nihlathak 0 Nihlathak Town +qual-kehk 515 qual-kehk 0 Qual-Kehk +catapultspotter1 516 catapultspotter1 catapultspotter2 0 Catapult Spotter S +catapultspotter2 517 catapultspotter1 catapultspotter3 1 Catapult Spotter E +catapultspotter3 518 catapultspotter1 catapultspotter4 2 Catapult Spotter Siege +catapultspotter4 519 catapultspotter1 3 Catapult Spotter W +cain6 520 cain6 0 DeckardCain +tyrael3 521 tyrael3 0 tyrael +act5barb1 522 act5barb1 0 Act 5 Combatant +act5barb2 523 act5barb2 0 Act 5 Combatant +barricadewall1 524 barricadewall1 barricadewall2 0 Barricade Wall Right +barricadewall2 525 barricadewall1 1 Barricade Wall Left +nihlathakboss 526 nihlathakboss 0 Nihlathak +drehyaiced 527 drehyaiced 0 Drehya +evilhut 528 evilhut 0 Evil hut +deathmauler1 529 deathmauler1 deathmauler2 0 Death Mauler1 +deathmauler2 530 deathmauler1 deathmauler3 1 Death Mauler2 +deathmauler3 531 deathmauler1 deathmauler4 2 Death Mauler3 +deathmauler4 532 deathmauler1 deathmauler5 3 Death Mauler4 +deathmauler5 533 deathmauler1 deathmauler6 4 Death Mauler5 +act5pow 534 act5pow 0 POW +act5barb3 535 act5barb3 act5barb4 0 Act 5 Townguard +act5barb4 536 act5barb3 1 Act 5 Townguard +ancientstatue1 537 ancientstatue1 ancientstatue2 0 Ancient Statue 1 +ancientstatue2 538 ancientstatue1 ancientstatue3 1 Ancient Statue 2 +ancientstatue3 539 ancientstatue1 2 Ancient Statue 3 +ancientbarb1 540 ancientbarb1 ancientbarb2 0 Ancient Barbarian 1 +ancientbarb2 541 ancientbarb1 ancientbarb3 1 Ancient Barbarian 2 +ancientbarb3 542 ancientbarb1 2 Ancient Barbarian 3 +baalthrone 543 baalthrone 0 Baal Throne +baalcrab 544 baalcrab 0 Baal Crab +baaltaunt 545 baaltaunt 0 Baal Taunt +putriddefiler1 546 putriddefiler1 putriddefiler2 0 Putrid Defiler1 +putriddefiler2 547 putriddefiler1 putriddefiler3 1 Putrid Defiler2 +putriddefiler3 548 putriddefiler1 putriddefiler4 2 Putrid Defiler3 +putriddefiler4 549 putriddefiler1 putriddefiler5 3 Putrid Defiler4 +putriddefiler5 550 putriddefiler1 4 Putrid Defiler5 +painworm1 551 painworm1 painworm2 0 Pain Worm1 +painworm2 552 painworm1 painworm3 1 Pain Worm2 +painworm3 553 painworm1 painworm4 2 Pain Worm3 +painworm4 554 painworm1 painworm5 3 Pain Worm4 +painworm5 555 painworm1 4 Pain Worm5 +bunny 556 bunny 0 Bunny +baalhighpriest 557 baalhighpriest 0 Council Member +venomlord 558 venomlord 0 VenomLord +baalcrabstairs 559 baalcrabstairs 0 Baal Crab to Stairs +act5hire1 560 act5hire1 act5hire2 0 Act 5 Hireling 1hs +act5hire2 561 act5hire1 1 Act 5 Hireling 2hs +baaltentacle1 562 baaltentacle1 baaltentacle2 0 Baal Tentacle +baaltentacle2 563 baaltentacle1 baaltentacle3 1 Baal Tentacle +baaltentacle3 564 baaltentacle1 baaltentacle4 2 Baal Tentacle +baaltentacle4 565 baaltentacle1 baaltentacle5 3 Baal Tentacle +baaltentacle5 566 baaltentacle1 4 Baal Tentacle +injuredbarb1 567 injuredbarb1 0 Injured Barbarian 1 +injuredbarb2 568 injuredbarb2 0 Injured Barbarian 2 +injuredbarb3 569 injuredbarb3 0 Injured Barbarian 3 +baalclone 570 baalclone 0 Baal Crab Clone +baalminion1 571 baalminion1 baalminion2 0 Baals Minion +baalminion2 572 baalminion1 baalminion3 1 Baals Minion +baalminion3 573 baalminion1 2 Baals Minion +worldstoneeffect 574 worldstoneeffect 0 Worldstone Effect +sk_archer6 575 sk_archer1 sk_archer7 3 BurningDeadArcher +sk_archer7 576 sk_archer1 sk_archer8 2 BoneArcher +sk_archer8 577 sk_archer1 sk_archer9 3 BurningDeadArcher +sk_archer9 578 sk_archer1 sk_archer10 1 ReturnedArcher +sk_archer10 579 sk_archer1 4 HorrorArcher +bighead6 580 bighead1 bighead7 4 Afflicted +bighead7 581 bighead1 bighead8 1 Tainted +bighead8 582 bighead1 bighead9 2 Misshapen +bighead9 583 bighead1 bighead10 3 Disfigured +bighead10 584 bighead1 0 Damned +goatman6 585 goatman1 goatman7 0 MoonClan +goatman7 586 goatman1 goatman8 1 NightClan +goatman8 587 goatman1 goatman9 2 HellClan +goatman9 588 goatman1 goatman10 3 BloodClan +goatman10 589 goatman1 4 DeathClan +foulcrow5 590 foulcrow1 foulcrow6 0 FoulCrow +foulcrow6 591 foulcrow1 foulcrow7 1 BloodHawk +foulcrow7 592 foulcrow1 foulcrow8 2 BlackRaptor +foulcrow8 593 foulcrow1 3 CloudStalker +clawviper6 594 clawviper1 clawviper7 4 ClawViper +clawviper7 595 clawviper1 clawviper8 4 PitViper +clawviper8 596 clawviper1 clawviper9 0 Salamander +clawviper9 597 clawviper1 clawviper10 1 TombViper +clawviper10 598 clawviper1 1 SerpentMagus +sandraider6 599 sandraider1 sandraider7 0 Marauder +sandraider7 600 sandraider1 sandraider8 1 Infidel +sandraider8 601 sandraider1 sandraider9 4 SandRaider +sandraider9 602 sandraider1 sandraider10 3 Invader +sandraider10 603 sandraider1 2 Assailant +deathmauler6 604 deathmauler1 0 Death Mauler1 +quillrat6 605 quillrat1 quillrat7 0 QuillRat +quillrat7 606 quillrat1 quillrat8 1 SpikeFiend +quillrat8 607 quillrat1 4 RazorSpine +vulture5 608 vulture1 0 CarrionBird +thornhulk5 609 thornhulk1 0 ThornedHulk +slinger7 610 slinger1 slinger8 0 Slinger +slinger8 611 slinger1 slinger9 1 Slinger +slinger9 612 slinger1 1 Slinger +cr_archer6 613 cr_archer1 cr_archer7 1 VileArcher +cr_archer7 614 cr_archer1 2 DarkArcher +cr_lancer6 615 cr_lancer1 cr_lancer7 1 VileLancer +cr_lancer7 616 cr_lancer1 cr_lancer8 2 DarkLancer +cr_lancer8 617 cr_lancer1 3 BlackLancer +blunderbore5 618 blunderbore1 blunderbore6 0 Blunderbore +blunderbore6 619 blunderbore1 2 Mauler +skmage_fire5 620 skmage_fire1 skmage_fire6 1 ReturnedMage +skmage_fire6 621 skmage_fire1 3 BurningDeadMage +skmage_ltng5 622 skmage_ltng1 skmage_ltng6 1 ReturnedMage +skmage_ltng6 623 skmage_ltng1 3 HorrorMage +skmage_cold5 624 skmage_cold1 2 BoneMage +skmage_pois5 625 skmage_pois1 skmage_pois6 4 HorrorMage +skmage_pois6 626 skmage_pois1 0 HorrorMage +pantherwoman5 627 pantherwoman1 pantherwoman6 0 Huntress +pantherwoman6 628 pantherwoman1 1 SaberCat +sandleaper6 629 sandleaper1 sandleaper7 1 CaveLeaper +sandleaper7 630 sandleaper1 3 TombCreeper +wraith6 631 wraith1 wraith7 0 Ghost +wraith7 632 wraith1 wraith8 0 Wraith +wraith8 633 wraith1 0 Specter +succubus6 634 succubus1 succubus7 0 Succubusexp +succubus7 635 succubus1 2 Hell Temptress +succubuswitch6 636 succubuswitch1 succubuswitch7 3 Dominus +succubuswitch7 637 succubuswitch1 succubuswitch8 4 Hell Witch +succubuswitch8 638 succubuswitch1 1 VileWitch +willowisp5 639 willowisp1 willowisp6 0 Gloam +willowisp6 640 willowisp1 willowisp7 3 BlackSoul +willowisp7 641 willowisp1 0 BurningSoul +fallen6 642 fallen1 fallen7 1 Carver +fallen7 643 fallen1 fallen8 2 Devilkin +fallen8 644 fallen1 0 DarkOne +fallenshaman6 645 fallenshaman1 fallenshaman7 1 CarverShaman +fallenshaman7 646 fallenshaman1 fallenshaman8 2 DevilkinShaman +fallenshaman8 647 fallenshaman1 0 DarkShaman +skeleton6 648 skeleton1 skeleton7 2 BoneWarrior +skeleton7 649 skeleton1 1 Returned +batdemon6 650 batdemon1 batdemon7 1 Gloombat +batdemon7 651 batdemon1 0 Fiend +bloodlord6 652 bloodlord1 bloodlord7 2 Blood Lord1 +bloodlord7 653 bloodlord1 3 Blood Lord4 +scarab6 654 scarab1 scarab7 2 Scarab +scarab7 655 scarab1 0 SteelWeevil +fetish6 656 fetish1 fetish7 1 Flayer +fetish7 657 fetish1 fetish8 0 StygianDoll +fetish8 658 fetish1 2 SoulKiller +fetishblow6 659 fetishblow1 fetishblow7 1 Flayer +fetishblow7 660 fetishblow1 fetishblow8 0 StygianDoll +fetishblow8 661 fetishblow1 2 SoulKiller +fetishshaman6 662 fetishshaman1 fetishshaman7 1 FlayerShaman +fetishshaman7 663 fetishshaman1 fetishshaman8 0 StygianDollShaman +fetishshaman8 664 fetishshaman1 2 SoulKillerShaman +baboon7 665 baboon1 baboon8 4 TempleGuard +baboon8 666 baboon1 3 TempleGuard +unraveler6 667 unraveler1 unraveler7 4 Guardian +unraveler7 668 unraveler1 unraveler8 2 Unraveler +unraveler8 669 unraveler1 unraveler9 4 Horadrim Ancient +unraveler9 670 unraveler1 2 Horadrim Ancient +zealot4 671 zealot1 zealot5 1 Zealot +zealot5 672 zealot1 2 Zealot +cantor5 673 cantor1 cantor6 1 Heirophant +cantor6 674 cantor1 2 Heirophant +vilemother4 675 vilemother1 vilemother5 2 Grotesque +vilemother5 676 vilemother1 0 FleshSpawner +vilechild4 677 vilechild1 vilechild5 2 GrotesqueWyrm +vilechild5 678 vilechild1 0 FleshBeast +sandmaggot6 679 sandmaggot1 4 WorldKiller +maggotbaby6 680 maggotbaby1 4 WorldKillerYoung +maggotegg6 681 maggotegg1 4 WorldKillerEgg +minion9 682 minion1 minion10 2 Slayerexp +minion10 683 minion1 minion11 3 HellSpawn +minion11 684 minion1 2 GreaterHellSpawn +arach6 685 arach1 0 Arach +megademon4 686 megademon1 megademon5 0 Balrog +megademon5 687 megademon1 0 PitLord +imp6 688 imp1 imp7 0 Imp1 +imp7 689 imp1 3 Imp4 +bonefetish6 690 bonefetish1 bonefetish7 2 Undead StygianDoll +bonefetish7 691 bonefetish1 2 Undead SoulKiller +fingermage4 692 fingermage1 fingermage5 1 Strangler +fingermage5 693 fingermage1 1 StormCaster +regurgitator4 694 regurgitator1 2 MawFiend +vampire6 695 vampire1 vampire7 3 BloodLord +vampire7 696 vampire1 vampire8 0 GhoulLord +vampire8 697 vampire1 3 DarkLord +reanimatedhorde6 698 reanimatedhorde1 0 UnholyCorpse +dkfig1 699 doomknight1 dkfig2 0 DoomKnight +dkfig2 700 doomknight1 0 DoomKnight +dkmag1 701 doomknight3 dkmag2 0 OblivionKnight +dkmag2 702 doomknight3 0 OblivionKnight +mummy6 703 mummy1 3 Cadaver \ No newline at end of file diff --git a/d2bs/kolbot/sdk/npcmenuid.txt b/d2bs/kolbot/sdk/npcmenuid.txt new file mode 100644 index 000000000..3df1e7e7b --- /dev/null +++ b/d2bs/kolbot/sdk/npcmenuid.txt @@ -0,0 +1,18 @@ +NPC Menu List: + +0x0D35 Talk +0x0D44 Trade +0x0D06 Trade/Repair +0x0FB1 Imbue +0x0D46 Gamble +0x0D45 Hire +0x0D36 Go East +0x0D37 Go West +0x0FB4 Identify Items +0x0D38 Sail East +0x0D39 Sail West +0x1507 Ressurect Merc +0x58DC Add Sockets +0x58DD Personalize +0x58D2 Travel to Harrogath + diff --git a/d2bs/kolbot/sdk/quests.txt b/d2bs/kolbot/sdk/quests.txt new file mode 100644 index 000000000..cf16dc851 --- /dev/null +++ b/d2bs/kolbot/sdk/quests.txt @@ -0,0 +1,46 @@ +Info from Mattir: + +int = me.getQuest( int QuestNumber , int QuestCompletion ); + +QuestNumber +0 = Spoke to Warriv +1 = Den of Evil +2 = Sisters' Burial Grounds +4 = The Search for Cain +5 = Forgotten Tower +3 = Tools of the Trade +6 = Sisters to the Slaughter +7 = Able to go to Act II +8 = Spoke to Jerhyn +9 = Radament's Lair +10 = The Horadric Staff +11 = The Tainted Sun +12 = The Arcane Sanctuary +13 = The Summoner +14 = The Seven Tombs +15 = Able to go to Act III +16 = Spoke to Hratli +20 = The Golden Bird +19 = Blade of the Old Religion +18 = Khalim's Will +17 = Lam Esen's Tome +21 = The Blackened Temple +22 = The Guardian +23 = Able to go to Act IV +24 = Spoke to Tyrael +25 = The Fallen Angel +27 = Hell's Forge +26 = Terror's End +28 = Able to go to Act V +35 = Seige on Haggorath +36 = Rescue on Mount Arreat +37 = Prison of Ice +38 = Betrayal of Haggorath +39 = Rite of Passage +40 = Eve of Destruction + +QuestCompletion +0 = Requirements Complete (Quest Complete) +2 = Quest Started +3-10 = Parts of Quest Complete Varies by Quest +12 = Quest Box Filled in diff --git a/d2bs/kolbot/sdk/roomstats.txt b/d2bs/kolbot/sdk/roomstats.txt new file mode 100644 index 000000000..42d0ff2e7 --- /dev/null +++ b/d2bs/kolbot/sdk/roomstats.txt @@ -0,0 +1,27 @@ +roomstats.txt +room.getStat(int); + +I don't know what all of this is, nor even very little. + + +From dlrgroom1: +0 xStart +1 yStart +2 xSize1 +3 ySize1 +4 xPos +5 yPos +6 xSize2 +7 ySize2 +8 + +From dlrgcoll: +9 nPosGameX +10 nPosGameY +11 nSizeGameX +12 nSizeGameY +13 nPosRoomX +14 nPosRoomY +15 nSizeRoomX +16 nSizeRoomY + diff --git a/d2bs/kolbot/sdk/skills.txt b/d2bs/kolbot/sdk/skills.txt new file mode 100644 index 000000000..0f83c2469 --- /dev/null +++ b/d2bs/kolbot/sdk/skills.txt @@ -0,0 +1,357 @@ +0 Attack +1 Kick +2 Throw +3 Unsummon +4 Left Hand Throw +5 Left Hand Swing +6 Magic Arrow +7 Fire Arrow +8 Inner Sight +9 Critical Strike +10 Jab +11 Cold Arrow +12 Multiple Shot +13 Dodge +14 Power Strike +15 Poison Javelin +16 Exploding Arrow +17 Slow Missiles +18 Avoid +19 Impale +20 Lightning Bolt +21 Ice Arrow +22 Guided Arrow +23 Penetrate +24 Charged Strike +25 Plague Javelin +26 Strafe +27 Immolation Arrow +28 Dopplezon +29 Evade +30 Fend +31 Freezing Arrow +32 Valkyrie +33 Pierce +34 Lightning Strike +35 Lightning Fury +36 Fire Bolt +37 Warmth +38 Charged Bolt +39 Ice Bolt +40 Frozen Armor +41 Inferno +42 Static Field +43 Telekinesis +44 Frost Nova +45 Ice Blast +46 Blaze +47 Fire Ball +48 Nova +49 Lightning +50 Shiver Armor +51 Fire Wall +52 Enchant +53 Chain Lightning +54 Teleport +55 Glacial Spike +56 Meteor +57 Thunder Storm +58 Energy Shield +59 Blizzard +60 Chilling Armor +61 Fire Mastery +62 Hydra +63 Lightning Mastery +64 Frozen Orb +65 Cold Mastery +66 Amplify Damage +67 Teeth +68 Bone Armor +69 Skeleton Mastery +70 Raise Skeleton +71 Dim Vision +72 Weaken +73 Poison Dagger +74 Corpse Explosion +75 Clay Golem +76 Iron Maiden +77 Terror +78 Bone Wall +79 Golem Mastery +80 Raise Skeletal Mage +81 Confuse +82 Life Tap +83 Poison Explosion +84 Bone Spear +85 BloodGolem +86 Attract +87 Decrepify +88 Bone Prison +89 Summon Resist +90 IronGolem +91 Lower Resist +92 Poison Nova +93 Bone Spirit +94 FireGolem +95 Revive +96 Sacrifice +97 Smite +98 Might +99 Prayer +100 Resist Fire +101 Holy Bolt +102 Holy Fire +103 Thorns +104 Defiance +105 Resist Cold +106 Zeal +107 Charge +108 Blessed Aim +109 Cleansing +110 Resist Lightning +111 Vengeance +112 Blessed Hammer +113 Concentration +114 Holy Freeze +115 Vigor +116 Conversion +117 Holy Shield +118 Holy Shock +119 Sanctuary +120 Meditation +121 Fist of the Heavens +122 Fanaticism +123 Conviction +124 Redemption +125 Salvation +126 Bash +127 Sword Mastery +128 Axe Mastery +129 Mace Mastery +130 Howl +131 Find Potion +132 Leap +133 Double Swing +134 Pole Arm Mastery +135 Throwing Mastery +136 Spear Mastery +137 Taunt +138 Shout +139 Stun +140 Double Throw +141 Increased Stamina +142 Find Item +143 Leap Attack +144 Concentrate +145 Iron Skin +146 Battle Cry +147 Frenzy +148 Increased Speed +149 Battle Orders +150 Grim Ward +151 Whirlwind +152 Berserk +153 Natural Resistance +154 War Cry +155 Battle Command +156 Fire Hit +157 UnHolyBolt +158 SkeletonRaise +159 MaggotEgg +160 ShamanFire +161 MagottUp +162 MagottDown +163 MagottLay +164 AndrialSpray +165 Jump +166 Swarm Move +167 Nest +168 Quick Strike +169 VampireFireball +170 VampireFirewall +171 VampireMeteor +172 GargoyleTrap +173 SpiderLay +174 VampireHeal +175 VampireRaise +176 Submerge +177 FetishAura +178 FetishInferno +179 ZakarumHeal +180 Emerge +181 Resurrect +182 Bestow +183 MissileSkill1 +184 MonTeleport +185 PrimeLightning +186 PrimeBolt +187 PrimeBlaze +188 PrimeFirewall +189 PrimeSpike +190 PrimeIceNova +191 PrimePoisonball +192 PrimePoisonNova +193 DiabLight +194 DiabCold +195 DiabFire +196 FingerMageSpider +197 DiabWall +198 DiabRun +199 DiabPrison +200 PoisonBallTrap +201 AndyPoisonBolt +202 HireableMissile +203 DesertTurret +204 ArcaneTower +205 MonBlizzard +206 Mosquito +207 CursedBallTrapRight +208 CursedBallTrapLeft +209 MonFrozenArmor +210 MonBoneArmor +211 MonBoneSpirit +212 MonCurseCast +213 HellMeteor +214 RegurgitatorEat +215 MonFrenzy +216 QueenDeath +217 Scroll of Identify +218 Book of Identify +219 Scroll of Townportal +220 Book of Townportal +221 Raven +222 Plague Poppy +223 Wearwolf +224 Shape Shifting +225 Firestorm +226 Oak Sage +227 Summon Spirit Wolf +228 Wearbear +229 Molten Boulder +230 Arctic Blast +231 Cycle of Life +232 Feral Rage +233 Maul +234 Eruption +235 Cyclone Armor +236 Heart of Wolverine +237 Summon Fenris +238 Rabies +239 Fire Claws +240 Twister +241 Vines +242 Hunger +243 Shock Wave +244 Volcano +245 Tornado +246 Spirit of Barbs +247 Summon Grizzly +248 Fury +249 Armageddon +250 Hurricane +251 Fire Trauma +252 Claw Mastery +253 Psychic Hammer +254 Tiger Strike +255 Dragon Talon +256 Shock Field +257 Blade Sentinel +258 Quickness +259 Fists of Fire +260 Dragon Claw +261 Charged Bolt Sentry +262 Wake of Fire Sentry +263 Weapon Block +264 Cloak of Shadows +265 Cobra Strike +266 Blade Fury +267 Fade +268 Shadow Warrior +269 Claws of Thunder +270 Dragon Tail +271 Lightning Sentry +272 Inferno Sentry +273 Mind Blast +274 Blades of Ice +275 Dragon Flight +276 Death Sentry +277 Blade Shield +278 Venom +279 Shadow Master +280 Royal Strike +281 Wake Of Destruction Sentry +282 Imp Inferno +283 Imp Fireball +284 Baal Taunt +285 Baal Corpse Explode +286 Baal Monster Spawn +287 Catapult Charged Ball +288 Catapult Spike Ball +289 Suck Blood +290 Cry Help +291 Healing Vortex +292 Teleport 2 +293 Self-resurrect +294 Vine Attack +295 Overseer Whip +296 Barbs Aura +297 Wolverine Aura +298 Oak Sage Aura +299 Imp Fire Missile +300 Impregnate +301 Siege Beast Stomp +302 MinionSpawner +303 CatapultBlizzard +304 CatapultPlague +305 CatapultMeteor +306 BoltSentry +307 CorpseCycler +308 DeathMaul +309 Defense Curse +310 Blood Mana +311 mon inferno sentry +312 mon death sentry +313 sentry lightning +314 fenris rage +315 Baal Tentacle +316 Baal Nova +317 Baal Inferno +318 Baal Cold Missiles +319 MegademonInferno +320 EvilHutSpawner +321 CountessFirewall +322 ImpBolt +323 Horror Arctic Blast +324 death sentry ltng +325 VineCycler +326 BearSmite +327 Resurrect2 +328 BloodLordFrenzy +329 Baal Teleport +330 Imp Teleport +331 Baal Clone Teleport +332 ZakarumLightning +333 VampireMissile +334 MephistoMissile +335 DoomKnightMissile +336 RogueMissile +337 HydraMissile +338 NecromageMissile +339 MonBow +340 MonFireArrow +341 MonColdArrow +342 MonExplodingArrow +343 MonFreezingArrow +344 MonPowerStrike +345 SuccubusBolt +346 MephFrostNova +347 MonIceSpear +348 ShamanIce +349 Diablogeddon +350 Delerium Change +351 NihlathakCorpseExplosion +352 SerpentCharge +353 Trap Nova +354 UnHolyBoltEx +355 ShamanFireEx +356 Imp Fire Missile Ex diff --git a/d2bs/kolbot/sdk/states.txt b/d2bs/kolbot/sdk/states.txt new file mode 100644 index 000000000..5cba48e0c --- /dev/null +++ b/d2bs/kolbot/sdk/states.txt @@ -0,0 +1,160 @@ +#define STATE_NONE 0 +#define STATE_FREEZE 1 +#define STATE_POISON 2 +#define STATE_RESISTFIRE 3 +#define STATE_RESISTCOLD 4 +#define STATE_RESISTLIGHT 5 +#define STATE_RESISTMAGIC 6 +#define STATE_PLAYERBODY 7 +#define STATE_RESISTALL 8 +#define STATE_AMPLIFYDAMAGE 9 +#define STATE_FROZENARMOR 10 +#define STATE_COLD 11 +#define STATE_INFERNO 12 +#define STATE_BLAZE 13 +#define STATE_BONEARMOR 14 +#define STATE_CONCENTRATE 15 +#define STATE_ENCHANT 16 +#define STATE_INNERSIGHT 17 +#define STATE_SKILL_MOVE 18 +#define STATE_WEAKEN 19 +#define STATE_CHILLINGARMOR 20 +#define STATE_STUNNED 21 +#define STATE_SPIDERLAY 22 +#define STATE_DIMVISION 23 +#define STATE_SLOWED 24 +#define STATE_FETISHAURA 25 +#define STATE_SHOUT 26 +#define STATE_TAUNT 27 +#define STATE_CONVICTION 28 +#define STATE_CONVICTED 29 +#define STATE_ENERGYSHIELD 30 +#define STATE_VENOMCLAWS 31 +#define STATE_BATTLEORDERS 32 +#define STATE_MIGHT 33 +#define STATE_PRAYER 34 +#define STATE_HOLYFIRE 35 +#define STATE_THORNS 36 +#define STATE_DEFIANCE 37 +#define STATE_THUNDERSTORM 38 +#define STATE_LIGHTNINGBOLT 39 +#define STATE_BLESSEDAIM 40 +#define STATE_STAMINA 41 +#define STATE_CONCENTRATION 42 +#define STATE_HOLYWIND 43 +#define STATE_HOLYWINDCOLD 44 +#define STATE_CLEANSING 45 +#define STATE_HOLYSHOCK 46 +#define STATE_SANCTUARY 47 +#define STATE_MEDITATION 48 +#define STATE_FANATICISM 49 +#define STATE_REDEMPTION 50 +#define STATE_BATTLECOMMAND 51 +#define STATE_PREVENTHEAL 52 +#define STATE_CONVERSION 53 +#define STATE_UNINTERRUPTABLE 54 +#define STATE_IRONMAIDEN 55 +#define STATE_TERROR 56 +#define STATE_ATTRACT 57 +#define STATE_LIFETAP 58 +#define STATE_CONFUSE 59 +#define STATE_DECREPIFY 60 +#define STATE_LOWERRESIST 61 +#define STATE_OPENWOUNDS 62 +#define STATE_DOPPLEZON 63 +#define STATE_CRITICALSTRIKE 64 +#define STATE_DODGE 65 +#define STATE_AVOID 66 +#define STATE_PENETRATE 67 +#define STATE_EVADE 68 +#define STATE_PIERCE 69 +#define STATE_WARMTH 70 +#define STATE_FIREMASTERY 71 +#define STATE_LIGHTNINGMASTERY 72 +#define STATE_COLDMASTERY 73 +#define STATE_SWORDMASTERY 74 +#define STATE_AXEMASTERY 75 +#define STATE_MACEMASTERY 76 +#define STATE_POLEARMMASTERY 77 +#define STATE_THROWINGMASTERY 78 +#define STATE_SPEARMASTERY 79 +#define STATE_INCREASEDSTAMINA 80 +#define STATE_IRONSKIN 81 +#define STATE_INCREASEDSPEED 82 +#define STATE_NATURALRESISTANCE 83 +#define STATE_FINGERMAGECURSE 84 +#define STATE_NOMANAREGEN 85 +#define STATE_JUSTHIT 86 +#define STATE_SLOWMISSILES 87 +#define STATE_SHIVERARMOR 88 +#define STATE_BATTLECRY 89 +#define STATE_BLUE 90 +#define STATE_RED 91 +#define STATE_DEATH_DELAY 92 +#define STATE_VALKYRIE 93 +#define STATE_FRENZY 94 +#define STATE_BERSERK 95 +#define STATE_REVIVE 96 +#define STATE_ITEMFULLSET 97 +#define STATE_SOURCEUNIT 98 +#define STATE_REDEEMED 99 +#define STATE_HEALTHPOT 100 +#define STATE_HOLYSHIELD 101 +#define STATE_JUST_PORTALED 102 +#define STATE_MONFRENZY 103 +#define STATE_CORPSE_NODRAW 104 +#define STATE_ALIGNMENT 105 +#define STATE_MANAPOT 106 +#define STATE_SHATTER 107 +#define STATE_SYNC_WARPED 108 +#define STATE_CONVERSION_SAVE 109 +#define STATE_PREGNANT 110 +#define STATE_111 111 +#define STATE_RABIES 112 +#define STATE_DEFENSE_CURSE 113 +#define STATE_BLOOD_MANA 114 +#define STATE_BURNING 115 +#define STATE_DRAGONFLIGHT 116 +#define STATE_MAUL 117 +#define STATE_CORPSE_NOSELECT 118 +#define STATE_SHADOWWARRIOR 119 +#define STATE_FERALRAGE 120 +#define STATE_SKILLDELAY 121 +#define STATE_PROGRESSIVE_DAMAGE 122 +#define STATE_PROGRESSIVE_STEAL 123 +#define STATE_PROGRESSIVE_OTHER 124 +#define STATE_PROGRESSIVE_FIRE 125 +#define STATE_PROGRESSIVE_COLD 126 +#define STATE_PROGRESSIVE_LIGHTNING 127 +#define STATE_SHRINE_ARMOR 128 +#define STATE_SHRINE_COMBAT 129 +#define STATE_SHRINE_RESIST_LIGHTNING 130 +#define STATE_SHRINE_RESIST_FIRE 131 +#define STATE_SHRINE_RESIST_COLD 132 +#define STATE_SHRINE_RESIST_POISON 133 +#define STATE_SHRINE_SKILL 134 +#define STATE_SHRINE_MANA_REGEN 135 +#define STATE_SHRINE_STAMINA 136 +#define STATE_SHRINE_EXPERIENCE 137 +#define STATE_FENRIS_RAGE 138 +#define STATE_WOLF 139 +#define STATE_BEAR 140 +#define STATE_BLOODLUST 141 +#define STATE_CHANGECLASS 142 +#define STATE_ATTACHED 143 +#define STATE_HURRICANE 144 +#define STATE_ARMAGEDDON 145 +#define STATE_INVIS 146 +#define STATE_BARBS 147 +#define STATE_WOLVERINE 148 +#define STATE_OAKSAGE 149 +#define STATE_VINE_BEAST 150 +#define STATE_CYCLONEARMOR 151 +#define STATE_CLAWMASTERY 152 +#define STATE_CLOAK_OF_SHADOWS 153 +#define STATE_RECYCLED 154 +#define STATE_WEAPONBLOCK 155 +#define STATE_CLOAKED 156 +#define STATE_QUICKNESS 157 +#define STATE_BLADESHIELD 158 +#define STATE_FADE 159 diff --git a/d2bs/kolbot/sdk/stats.txt b/d2bs/kolbot/sdk/stats.txt new file mode 100644 index 000000000..ee5b67091 --- /dev/null +++ b/d2bs/kolbot/sdk/stats.txt @@ -0,0 +1,360 @@ +0 strength +1 energy +2 dexterity +3 vitality +4 statpts +5 newskills +6 hitpoints +7 maxhp +8 mana +9 maxmana +10 stamina +11 maxstamina +12 level +13 experience +14 gold +15 goldbank +16 item_armor_percent +17 item_maxdamage_percent +18 item_mindamage_percent +19 tohit +20 toblock +21 mindamage +22 maxdamage +23 secondary_mindamage +24 secondary_maxdamage +25 damagepercent +26 manarecovery +27 manarecoverybonus +28 staminarecoverybonus +29 lastexp +30 nextexp +31 armorclass +32 armorclass_vs_missile +33 armorclass_vs_hth +34 normal_damage_reduction +35 magic_damage_reduction +36 damageresist +37 magicresist +38 maxmagicresist +39 fireresist +40 maxfireresist +41 lightresist +42 maxlightresist +43 coldresist +44 maxcoldresist +45 poisonresist +46 maxpoisonresist +47 damageaura +48 firemindam +49 firemaxdam +50 lightmindam +51 lightmaxdam +52 magicmindam +53 magicmaxdam +54 coldmindam +55 coldmaxdam +56 coldlength +57 poisonmindam +58 poisonmaxdam +59 poisonlength +60 lifedrainmindam +61 lifedrainmaxdam +62 manadrainmindam +63 manadrainmaxdam +64 stamdrainmindam +65 stamdrainmaxdam +66 stunlength +67 velocitypercent +68 attackrate +69 other_animrate +70 quantity +71 value +72 durability +73 maxdurability +74 hpregen +75 item_maxdurability_percent +76 item_maxhp_percent +77 item_maxmana_percent +78 item_attackertakesdamage +79 item_goldbonus +80 item_magicbonus +81 item_knockback +82 item_timeduration +83 item_addclassskills +84 unsentparam1 +85 item_addexperience +86 item_healafterkill +87 item_reducedprices +88 item_doubleherbduration +89 item_lightradius +90 item_lightcolor +91 item_req_percent +92 item_levelreq +93 item_fasterattackrate +94 item_levelreqpct +95 lastblockframe +96 item_fastermovevelocity +97 item_nonclassskill +98 state +99 item_fastergethitrate +100 monster_playercount +101 skill_poison_override_length +102 item_fasterblockrate +103 skill_bypass_undead +104 skill_bypass_demons +105 item_fastercastrate +106 skill_bypass_beasts +107 item_singleskill +108 item_restinpeace +109 curse_resistance +110 item_poisonlengthresist +111 item_normaldamage +112 item_howl +113 item_stupidity +114 item_damagetomana +115 item_ignoretargetac +116 item_fractionaltargetac +117 item_preventheal +118 item_halffreezeduration +119 item_tohit_percent +120 item_damagetargetac +121 item_demondamage_percent +122 item_undeaddamage_percent +123 item_demon_tohit +124 item_undead_tohit +125 item_throwable +126 item_elemskill +127 item_allskills +128 item_attackertakeslightdamage +129 ironmaiden_level +130 lifetap_level +131 thorns_percent +132 bonearmor +133 bonearmormax +134 item_freeze +135 item_openwounds +136 item_crushingblow +137 item_kickdamage +138 item_manaafterkill +139 item_healafterdemonkill +140 item_extrablood +141 item_deadlystrike +142 item_absorbfire_percent +143 item_absorbfire +144 item_absorblight_percent +145 item_absorblight +146 item_absorbmagic_percent +147 item_absorbmagic +148 item_absorbcold_percent +149 item_absorbcold +150 item_slow +151 item_aura +152 item_indesctructible +153 item_cannotbefrozen +154 item_staminadrainpct +155 item_reanimate +156 item_pierce +157 item_magicarrow +158 item_explosivearrow +159 item_throw_mindamage +160 item_throw_maxdamage +161 skill_handofathena +162 skill_staminapercent +163 skill_passive_staminapercent +164 skill_concentration +165 skill_enchant +166 skill_pierce +167 skill_conviction +168 skill_chillingarmor +169 skill_frenzy +170 skill_decrepify +171 skill_armor_percent +172 alignment +173 target0 +174 target1 +175 goldlost +176 conversion_level +177 conversion_maxhp +178 unit_dooverlay +179 attack_vs_montype +180 damage_vs_montype +181 fade +182 armor_override_percent +183 unused183 +184 unused184 +185 unused185 +186 unused186 +187 unused187 +188 item_addskill_tab +189 unused189 +190 unused190 +191 unused191 +192 unused192 +193 unused193 +194 item_numsockets +195 item_skillonattack +196 item_skillonkill +197 item_skillondeath +198 item_skillonhit +199 item_skillonlevelup +200 unused200 +201 item_skillongethit +202 unused202 +203 unused203 +204 item_charged_skill +205 unused204 +206 unused205 +207 unused206 +208 unused207 +209 unused208 +210 unused209 +211 unused210 +212 unused211 +213 unused212 +214 item_armor_perlevel +215 item_armorpercent_perlevel +216 item_hp_perlevel +217 item_mana_perlevel +218 item_maxdamage_perlevel +219 item_maxdamage_percent_perlevel +220 item_strength_perlevel +221 item_dexterity_perlevel +222 item_energy_perlevel +223 item_vitality_perlevel +224 item_tohit_perlevel +225 item_tohitpercent_perlevel +226 item_cold_damagemax_perlevel +227 item_fire_damagemax_perlevel +228 item_ltng_damagemax_perlevel +229 item_pois_damagemax_perlevel +230 item_resist_cold_perlevel +231 item_resist_fire_perlevel +232 item_resist_ltng_perlevel +233 item_resist_pois_perlevel +234 item_absorb_cold_perlevel +235 item_absorb_fire_perlevel +236 item_absorb_ltng_perlevel +237 item_absorb_pois_perlevel +238 item_thorns_perlevel +239 item_find_gold_perlevel +240 item_find_magic_perlevel +241 item_regenstamina_perlevel +242 item_stamina_perlevel +243 item_damage_demon_perlevel +244 item_damage_undead_perlevel +245 item_tohit_demon_perlevel +246 item_tohit_undead_perlevel +247 item_crushingblow_perlevel +248 item_openwounds_perlevel +249 item_kick_damage_perlevel +250 item_deadlystrike_perlevel +251 item_find_gems_perlevel +252 item_replenish_durability +253 item_replenish_quantity +254 item_extra_stack +255 item_find_item +256 item_slash_damage +257 item_slash_damage_percent +258 item_crush_damage +259 item_crush_damage_percent +260 item_thrust_damage +261 item_thrust_damage_percent +262 item_absorb_slash +263 item_absorb_crush +264 item_absorb_thrust +265 item_absorb_slash_percent +266 item_absorb_crush_percent +267 item_absorb_thrust_percent +268 item_armor_bytime +269 item_armorpercent_bytime +270 item_hp_bytime +271 item_mana_bytime +272 item_maxdamage_bytime +273 item_maxdamage_percent_bytime +274 item_strength_bytime +275 item_dexterity_bytime +276 item_energy_bytime +277 item_vitality_bytime +278 item_tohit_bytime +279 item_tohitpercent_bytime +280 item_cold_damagemax_bytime +281 item_fire_damagemax_bytime +282 item_ltng_damagemax_bytime +283 item_pois_damagemax_bytime +284 item_resist_cold_bytime +285 item_resist_fire_bytime +286 item_resist_ltng_bytime +287 item_resist_pois_bytime +288 item_absorb_cold_bytime +289 item_absorb_fire_bytime +290 item_absorb_ltng_bytime +291 item_absorb_pois_bytime +292 item_find_gold_bytime +293 item_find_magic_bytime +294 item_regenstamina_bytime +295 item_stamina_bytime +296 item_damage_demon_bytime +297 item_damage_undead_bytime +298 item_tohit_demon_bytime +299 item_tohit_undead_bytime +300 item_crushingblow_bytime +301 item_openwounds_bytime +302 item_kick_damage_bytime +303 item_deadlystrike_bytime +304 item_find_gems_bytime +305 item_pierce_cold +306 item_pierce_fire +307 item_pierce_ltng +308 item_pierce_pois +309 item_damage_vs_monster +310 item_damage_percent_vs_monster +311 item_tohit_vs_monster +312 item_tohit_percent_vs_monster +313 item_ac_vs_monster +314 item_ac_percent_vs_monster +315 firelength +316 burningmin +317 burningmax +318 progressive_damage +319 progressive_steal +320 progressive_other +321 progressive_fire +322 progressive_cold +323 progressive_lightning +324 item_extra_charges +325 progressive_tohit +326 poison_count +327 damage_framerate +328 pierce_idx +329 passive_fire_mastery +330 passive_ltng_mastery +331 passive_cold_mastery +332 passive_pois_mastery +333 passive_fire_pierce +334 passive_ltng_pierce +335 passive_cold_pierce +336 passive_pois_pierce +337 passive_critical_strike +338 passive_dodge +339 passive_avoid +340 passive_evade +341 passive_warmth +342 passive_mastery_melee_th +343 passive_mastery_melee_dmg +344 passive_mastery_melee_crit +345 passive_mastery_throw_th +346 passive_mastery_throw_dmg +347 passive_mastery_throw_crit +348 passive_weaponblock +349 passive_summon_resist +350 modifierlist_skill +351 modifierlist_level +352 last_sent_hp_pct +353 source_unit_type +354 source_unit_id +355 shortparam1 +356 questitemdifficulty +357 passive_mag_mastery +358 passive_mag_pierce + diff --git a/d2bs/kolbot/sdk/stats_skills.txt b/d2bs/kolbot/sdk/stats_skills.txt new file mode 100644 index 000000000..0f83c2469 --- /dev/null +++ b/d2bs/kolbot/sdk/stats_skills.txt @@ -0,0 +1,357 @@ +0 Attack +1 Kick +2 Throw +3 Unsummon +4 Left Hand Throw +5 Left Hand Swing +6 Magic Arrow +7 Fire Arrow +8 Inner Sight +9 Critical Strike +10 Jab +11 Cold Arrow +12 Multiple Shot +13 Dodge +14 Power Strike +15 Poison Javelin +16 Exploding Arrow +17 Slow Missiles +18 Avoid +19 Impale +20 Lightning Bolt +21 Ice Arrow +22 Guided Arrow +23 Penetrate +24 Charged Strike +25 Plague Javelin +26 Strafe +27 Immolation Arrow +28 Dopplezon +29 Evade +30 Fend +31 Freezing Arrow +32 Valkyrie +33 Pierce +34 Lightning Strike +35 Lightning Fury +36 Fire Bolt +37 Warmth +38 Charged Bolt +39 Ice Bolt +40 Frozen Armor +41 Inferno +42 Static Field +43 Telekinesis +44 Frost Nova +45 Ice Blast +46 Blaze +47 Fire Ball +48 Nova +49 Lightning +50 Shiver Armor +51 Fire Wall +52 Enchant +53 Chain Lightning +54 Teleport +55 Glacial Spike +56 Meteor +57 Thunder Storm +58 Energy Shield +59 Blizzard +60 Chilling Armor +61 Fire Mastery +62 Hydra +63 Lightning Mastery +64 Frozen Orb +65 Cold Mastery +66 Amplify Damage +67 Teeth +68 Bone Armor +69 Skeleton Mastery +70 Raise Skeleton +71 Dim Vision +72 Weaken +73 Poison Dagger +74 Corpse Explosion +75 Clay Golem +76 Iron Maiden +77 Terror +78 Bone Wall +79 Golem Mastery +80 Raise Skeletal Mage +81 Confuse +82 Life Tap +83 Poison Explosion +84 Bone Spear +85 BloodGolem +86 Attract +87 Decrepify +88 Bone Prison +89 Summon Resist +90 IronGolem +91 Lower Resist +92 Poison Nova +93 Bone Spirit +94 FireGolem +95 Revive +96 Sacrifice +97 Smite +98 Might +99 Prayer +100 Resist Fire +101 Holy Bolt +102 Holy Fire +103 Thorns +104 Defiance +105 Resist Cold +106 Zeal +107 Charge +108 Blessed Aim +109 Cleansing +110 Resist Lightning +111 Vengeance +112 Blessed Hammer +113 Concentration +114 Holy Freeze +115 Vigor +116 Conversion +117 Holy Shield +118 Holy Shock +119 Sanctuary +120 Meditation +121 Fist of the Heavens +122 Fanaticism +123 Conviction +124 Redemption +125 Salvation +126 Bash +127 Sword Mastery +128 Axe Mastery +129 Mace Mastery +130 Howl +131 Find Potion +132 Leap +133 Double Swing +134 Pole Arm Mastery +135 Throwing Mastery +136 Spear Mastery +137 Taunt +138 Shout +139 Stun +140 Double Throw +141 Increased Stamina +142 Find Item +143 Leap Attack +144 Concentrate +145 Iron Skin +146 Battle Cry +147 Frenzy +148 Increased Speed +149 Battle Orders +150 Grim Ward +151 Whirlwind +152 Berserk +153 Natural Resistance +154 War Cry +155 Battle Command +156 Fire Hit +157 UnHolyBolt +158 SkeletonRaise +159 MaggotEgg +160 ShamanFire +161 MagottUp +162 MagottDown +163 MagottLay +164 AndrialSpray +165 Jump +166 Swarm Move +167 Nest +168 Quick Strike +169 VampireFireball +170 VampireFirewall +171 VampireMeteor +172 GargoyleTrap +173 SpiderLay +174 VampireHeal +175 VampireRaise +176 Submerge +177 FetishAura +178 FetishInferno +179 ZakarumHeal +180 Emerge +181 Resurrect +182 Bestow +183 MissileSkill1 +184 MonTeleport +185 PrimeLightning +186 PrimeBolt +187 PrimeBlaze +188 PrimeFirewall +189 PrimeSpike +190 PrimeIceNova +191 PrimePoisonball +192 PrimePoisonNova +193 DiabLight +194 DiabCold +195 DiabFire +196 FingerMageSpider +197 DiabWall +198 DiabRun +199 DiabPrison +200 PoisonBallTrap +201 AndyPoisonBolt +202 HireableMissile +203 DesertTurret +204 ArcaneTower +205 MonBlizzard +206 Mosquito +207 CursedBallTrapRight +208 CursedBallTrapLeft +209 MonFrozenArmor +210 MonBoneArmor +211 MonBoneSpirit +212 MonCurseCast +213 HellMeteor +214 RegurgitatorEat +215 MonFrenzy +216 QueenDeath +217 Scroll of Identify +218 Book of Identify +219 Scroll of Townportal +220 Book of Townportal +221 Raven +222 Plague Poppy +223 Wearwolf +224 Shape Shifting +225 Firestorm +226 Oak Sage +227 Summon Spirit Wolf +228 Wearbear +229 Molten Boulder +230 Arctic Blast +231 Cycle of Life +232 Feral Rage +233 Maul +234 Eruption +235 Cyclone Armor +236 Heart of Wolverine +237 Summon Fenris +238 Rabies +239 Fire Claws +240 Twister +241 Vines +242 Hunger +243 Shock Wave +244 Volcano +245 Tornado +246 Spirit of Barbs +247 Summon Grizzly +248 Fury +249 Armageddon +250 Hurricane +251 Fire Trauma +252 Claw Mastery +253 Psychic Hammer +254 Tiger Strike +255 Dragon Talon +256 Shock Field +257 Blade Sentinel +258 Quickness +259 Fists of Fire +260 Dragon Claw +261 Charged Bolt Sentry +262 Wake of Fire Sentry +263 Weapon Block +264 Cloak of Shadows +265 Cobra Strike +266 Blade Fury +267 Fade +268 Shadow Warrior +269 Claws of Thunder +270 Dragon Tail +271 Lightning Sentry +272 Inferno Sentry +273 Mind Blast +274 Blades of Ice +275 Dragon Flight +276 Death Sentry +277 Blade Shield +278 Venom +279 Shadow Master +280 Royal Strike +281 Wake Of Destruction Sentry +282 Imp Inferno +283 Imp Fireball +284 Baal Taunt +285 Baal Corpse Explode +286 Baal Monster Spawn +287 Catapult Charged Ball +288 Catapult Spike Ball +289 Suck Blood +290 Cry Help +291 Healing Vortex +292 Teleport 2 +293 Self-resurrect +294 Vine Attack +295 Overseer Whip +296 Barbs Aura +297 Wolverine Aura +298 Oak Sage Aura +299 Imp Fire Missile +300 Impregnate +301 Siege Beast Stomp +302 MinionSpawner +303 CatapultBlizzard +304 CatapultPlague +305 CatapultMeteor +306 BoltSentry +307 CorpseCycler +308 DeathMaul +309 Defense Curse +310 Blood Mana +311 mon inferno sentry +312 mon death sentry +313 sentry lightning +314 fenris rage +315 Baal Tentacle +316 Baal Nova +317 Baal Inferno +318 Baal Cold Missiles +319 MegademonInferno +320 EvilHutSpawner +321 CountessFirewall +322 ImpBolt +323 Horror Arctic Blast +324 death sentry ltng +325 VineCycler +326 BearSmite +327 Resurrect2 +328 BloodLordFrenzy +329 Baal Teleport +330 Imp Teleport +331 Baal Clone Teleport +332 ZakarumLightning +333 VampireMissile +334 MephistoMissile +335 DoomKnightMissile +336 RogueMissile +337 HydraMissile +338 NecromageMissile +339 MonBow +340 MonFireArrow +341 MonColdArrow +342 MonExplodingArrow +343 MonFreezingArrow +344 MonPowerStrike +345 SuccubusBolt +346 MephFrostNova +347 MonIceSpear +348 ShamanIce +349 Diablogeddon +350 Delerium Change +351 NihlathakCorpseExplosion +352 SerpentCharge +353 Trap Nova +354 UnHolyBoltEx +355 ShamanFireEx +356 Imp Fire Missile Ex diff --git a/d2bs/kolbot/sdk/stats_tabs.txt b/d2bs/kolbot/sdk/stats_tabs.txt new file mode 100644 index 000000000..2f8d9d3ff --- /dev/null +++ b/d2bs/kolbot/sdk/stats_tabs.txt @@ -0,0 +1,26 @@ +item.getStat( 188, tab ); // lookup table + +0 Bow and Crossbow Skills +1 Passive and Magic Skills +2 Javelin and Spear Skills +8 Fire Skills +9 Lightning Skills +10 Cold Skills +16 Curses Skills +17 Poison and Bone Skills +18 Necromancer Summoning Skills +24 Paladin Combat Skills +25 Offensive Auras Skills +26 Defensive Auras Skills +32 Barbarian Combat Skills +33 Masteries Skills +34 Warcries Skills +40 Druid Summoning Skills +41 Shape Shifting Skills +42 Elemental Skills +48 Traps Skills +49 Shadow Disciplines Skills +50 Martial Arts Skills + + +-- thanks to TheDesertWind for this list diff --git a/d2bs/kolbot/sdk/superunique_presetunitids.txt b/d2bs/kolbot/sdk/superunique_presetunitids.txt new file mode 100644 index 000000000..1b603621f --- /dev/null +++ b/d2bs/kolbot/sdk/superunique_presetunitids.txt @@ -0,0 +1,93 @@ +Super Unique PresetUnit Ids: + +*this list is correct to the best of my knowledge + +Id Name +250 The Summoner +704 Bishibosh +705 Bonebreak +706 Coldcrow +707 Rakanishu +708 Treehead WoodFist +709 Griswold +710 The Countess +711 Pitspawn Fouldog +712 Flamespike the Crawler +713 Boneash +714 Radament +715 Bloodwitch the Wild +716 Fangskin +717 Beetleburst +718 Leatherarm +719 Coldworm the Burrower +720 Fire Eye +721 Dark Elder +723 Ancient Kaa the Soulless +724 The Smith +725 Web Mage the Burning +726 Witch Doctor Endugu +727 Stormtree +728 Sarina the Battlemaid +729 Icehawk Riftwing +730 Ismail Vilehand +731 Geleb Flamefinger +732 Bremm Sparkfist +733 Toorc Icefist +734 Wyand Voidfinger +735 Maffer Dragonhand +736 Winged Death +737 The Tormentor +738 Taintbreeder +739 Riftwraith the Cannibal +740 Infector of Souls +741 Lord De Seis +742 Grand Vizier of Chaos +743 The Cow King +744 Corpsefire +745 Hephasto (The Feature Creep) +746 Siege Boss +747 Ancient Barbarian 1 +748 Ancient Barbarian 2 +749 Ancient Barbarian 3 +750 Axe Dweller +751 Bonesaw Breaker +752 Dac Farren +753 Eldritch (Megaflow Rectifier) +754 Eyeback Unleashed +755 Threash Socket +756 Pindleskin +757 Snapchip Shatter +758 Anodized Elite +759 Vinvear Molech +760 Sharp Tooth Sayer +761 Magma Torquer +762 Blaze Ripper +763 Frozenstein +764 Nihlathak Boss +765 Baal Subject 1 +766 Baal Subject 2 +767 Baal Subject 3 +768 Baal Subject 4 +769 Baal Subject 5 + + + +--- not in super unique list, but still have a weird Ids: (thanks to mousepad for helping fill this in!) + +772 random boss pack? +773 random champ pack? +774 Flavie +775 Blood Raven +778 maggot queen (broken?) +780,781 tenticles +787 flayers +788 flayer+shaman +792 ratmen +793 ratmen+shaman +794 demonimp pack +796 enslaved pack +795,797,798 ?? +799 dead enslaved +800 dead demonimp +801 dead barb +802 dead prowlingdead diff --git a/d2bs/kolbot/sdk/tile.d2l b/d2bs/kolbot/sdk/tile.d2l new file mode 100644 index 000000000..f6f6d2b39 --- /dev/null +++ b/d2bs/kolbot/sdk/tile.d2l @@ -0,0 +1,197 @@ +var tilelist=new Array(); + +function buildTileList() { + for (i=0; i<200; i++) { + tilelist[i]=new Array(); + } + //Act 1 (Complete) + tilelist[2][8]=2; // Den + tilelist[8][2]=4; // Den Out + tilelist[3][9]=3; // Cave + tilelist[9][13]=5; //Cave-Cave level 2 + tilelist[13][9]=4; //Cave Level 2 - Cave + tilelist[9][3]=4; // Cave out + tilelist[4][10]=1; // Undergounrd - Darien variation 1 + tilelist[4][1000]=3; // Undergounrd - Darien variation 1 + tilelist[4][1001]=0; // Undergounrd - Darien variation 1 + tilelist[10][4]=4; // Underground-stoney + tilelist[10][14]=5; // underground-underground2 + tilelist[14][10]=4; // underground2-underground + tilelist[10][5]=4; // Underground-dark wood + tilelist[5][10]=1; // Dark Wood-Underground + tilelist[6][11]=3; // Black Marsh - Hole + tilelist[11][6]=4; // Hole - Black Marsh + tilelist[11][15]=5; // Hole - Hole Level 2 + tilelist[15][11]=4; // Hole Level 2 - Hole + tilelist[6][20]=10; // Black Marsh - Forgotten Tower + tilelist[20][6]=11; // Forgotten Tower - Black Marsh + tilelist[20][21]=12; // Forgotten Tower - Tower Level 1 + tilelist[21][20]=8; // Tower Level 1 - Forgotten Tower + tilelist[21][22]=9; // Tower Level 1 - Tower Level 2 + tilelist[22][21]=8; // Tower Level 2- Tower Level 1 + tilelist[22][23]=9; // Tower Level 2 - Tower Level 3 + tilelist[23][22]=8; // Tower Level 3 - Tower Level 2 + tilelist[23][24]=9; // Tower Level 3 - Tower Level 4 + tilelist[24][23]=8; // Tower Level 4 - Tower Level 3 + tilelist[24][25]=9; // Tower Level 4 - Tower Level 5 + tilelist[25][24]=8; // Tower Level 5 - Tower Level 4 + tilelist[7][12]=2; // Tamoe - Pit + tilelist[7][120]=3; // Tamoe - Pit - Darien variation 1 + tilelist[12][7]=4; // Pit - Tamoe + tilelist[12][16]=5; // Pit - Pit level 2 + tilelist[16][12]=4; // Pit Level 2 - Pit + tilelist[28][29]=14; // Barracks - Jail Level 1 + tilelist[29][28]=13; // Jail Level 1 - Barracks + tilelist[29][30]=14; // Jail Level 1 - Jail Level 2 + tilelist[30][29]=13; // Jail Level 2 - Jail Level 1 + tilelist[30][31]=14; // Jail Level 2 - Jail Level 3 + tilelist[31][30]=13; // Jail Level 3 - Jail Level 2 + tilelist[31][32]=13; // Jail Level 3 - Inner Cloister + tilelist[32][31]=14; // Inner Cloister - Jail Level 3 + tilelist[33][34]=15; // Cathedral - Cat Level 1 + tilelist[34][33]=16; // Cat Level 1 - Cathedral + tilelist[34][35]=18; // Cat Level 1 - Cat Level 2 + tilelist[35][34]=17; // Cat Level 2 - Cat Level 1 + tilelist[35][36]=18; // Cat Level 2 - Cat Level 3 + tilelist[36][35]=17; // Cat Level 3 - Cat Level 2 + tilelist[36][37]=18; // Cat Level 3 - Cat Level 4 + tilelist[37][36]=17; // Cat Level 4 - Cat Level 3 + + // Act2 + tilelist[40][47]=19; // Lut - Sewers Level 1 (trap door) + //tilelist[40][47]=20; // Lut - Sewers Level 1 (seaside) + //tilelist[47][40]=21; // Sewers Level 1 - Lut (seaside) + tilelist[47][40]=22; // Sewers Level 1- Lut (trap door) + tilelist[47][48]=23; // Sewers Level 1 - Sewers Level 2 + tilelist[48][47]=22; // Sewers Level 2 - Sewers Level 1 + tilelist[48][49]=23; // Sewers Level 2 - Sewers Level 3 + tilelist[49][48]=22; // Sewers Level 3 - Sewers Level 2 + tilelist[41][55]=34; // Rocky Waste - Stoney Tomb 1 + tilelist[55][41]=45; // Stoney Tomb 1 - Rocky Waste + tilelist[55][59]=46; // Stoney Tomb 1 - Stoney Tomb 2 + tilelist[59][55]=45; // Stoney Tomb 2 - Stoney Tomb 1 + tilelist[42][56]=33; // Dry Hills - Halls 1 + tilelist[42][560]=34; // Dry Hills - Halls 1 - Darien variation 1 + tilelist[42][561]=35; // Dry Hills - Halls 1 - Darien variation 2 + tilelist[42][562]=36; // Dry Hills - Halls 1 - Darien variation 3 + tilelist[56][42]=45; // Halls 1 - Dry Hills + tilelist[56][57]=46; // Halls 1 - Halls 2 + tilelist[57][56]=45; // Halls 2 - Halls 1 + tilelist[57][60]=46; // Halls 2 - Halls 3 + tilelist[60][57]=45; // Halls 3 - Halls 2 + tilelist[43][62]=47; // Far Oasis - Maggot 1 + tilelist[62][43]=48; // Maggot 1 - Far Oasis + tilelist[62][63]=49; // Maggot 1 - Maggot 2 + tilelist[63][62]=48; // Maggot 2 - Maggot 1 + tilelist[63][64]=49; // Maggot 2 - Maggot 3 + tilelist[64][63]=48; // Maggot 3 - Maggot 2 + tilelist[44][65]=50; // Lost City - Ancient Tunnels + tilelist[65][44]=22; // Ancient Tunnels - Lost City + tilelist[45][58]=37; // Valley of Snakes - Claw Viper 1 + tilelist[58][45]=45; // Claw Viper 1 - Valley of Snakes + tilelist[58][61]=46; // Claw Viper 1 - Claw Viper 2 ///Darien Fix + tilelist[61][58]=45; // Claw Viper 2 - Claw Viper 1 ///Darien Fix + tilelist[40][50]=24; // Lut - Harem + tilelist[50][40]=25; // Harem - Lut + tilelist[50][51]=29; // Harem - Harem 2 (down/left) + tilelist[51][50]=27; // Harem 2 - Harem (down/left) + tilelist[51][52]=29; // Harem 2 - Palace Level 1 (down/left) + tilelist[52][53]=32; // Palace 1 - Palace 2 (down/left) + tilelist[53][52]=31; // Palace 2 - Palace 1 (down/left) + tilelist[53][54]=32; // Palace 2 - Palace 3 (down/left) + tilelist[54][53]=31; // Palace 3 - Palace 2 (down/left) + tilelist[46][66]=38; // Canyon - Tomb 1 + tilelist[46][67]=39; // Canyon - Tomb 2 + tilelist[46][68]=40; // Canyon - Tomb 3 + tilelist[46][69]=41; // Canyon - Tomb 4 + tilelist[46][70]=42; // Canyon - Tomb 5 + tilelist[46][71]=43; // Canyon - Tomb 6 + tilelist[46][72]=44; // Canyon - Tomb 7 + tilelist[66][46]=45; // Tomb 1 - Canyon + tilelist[67][46]=45; // Tomb 2 - Canyon + tilelist[68][46]=45; // Tomb 3 - Canyon + tilelist[69][46]=45; // Tomb 4 - Canyon + tilelist[70][46]=45; // Tomb 5 - Canyon + tilelist[71][46]=45; // Tomb 6 - Canyon + tilelist[72][46]=45; // Tomb 7 - Canyon + + //Act3 + tilelist[101][102]=67; // Durance 3 + tilelist[101][1021]=68; // Durance 3 - Darien variation 1 + + //Act4 (Complete) + tilelist[106][107]=69; // City of the Damned - River of Flame + tilelist[107][106]=70; // River - City + + //Act5 (NOT Complete) + tilelist[112][113]=71; // Arreat Plateau - Crystaline Passage + tilelist[113][112]=73; // Crystaline - Arreat Plateau + tilelist[113][115]=74; // Crystaline - Glacial Trail + tilelist[113][114]=75; // Crystaline - Frozen River + tilelist[114][113]=73; // Frozen River - Crystaline + tilelist[115][113]=73; // Glacial Trail - Crystaline + tilelist[115][116]=75; // Glacial - Drifter Cavern + tilelist[116][115]=73; // Drifter - Glacial + tilelist[115][117]=74; // Glacial - Tundra + tilelist[117][115]=72; // Tundra - Glacial + tilelist[117][118]=71; // Tundra - Ancient's Way + tilelist[118][117]=73; // Ancient's Way - Tundra + tilelist[118][119]=75; // Ancient's Way - Icey Cellar + tilelist[119][118]=73; // Icey Cellar - Ancient's Way + tilelist[118][120]=74; // Ancient's Way - Arreat Summit + tilelist[120][118]=79; // Arreat Summit - Ancient's Way + tilelist[120][128]=80; // Arreat Summit - Worldstone Level 1 + tilelist[128][120]=81; // Worldstone Level 1 - Arreat Summit + tilelist[121][122]=76; // Nhilithaks Temple - Halls 1 + tilelist[122][121]=78; // Halls 1 - Nhilithaks Temple + tilelist[122][133]=77; // Halls 1 - Halls 2 + tilelist[123][122]=78; // Halls 2 - Halls 1 + tilelist[123][124]=77; // Halls 2 - Halls 3 + tilelist[124][123]=78; // Halls 3 - Halls 2 + tilelist[129][130]=82; // WorldStone Keep Level 2 - WorldStone Keep Level 3 Added by Darien + tilelist[130][129]=81; // WorldStone Keep Level 3 - WorldStone Keep Level 2 Added by Darien + tilelist[130][131]=82; // WorldStone Keep Level 3 - Throne of Destruction Added by Darien + tilelist[131][130]=81; // Throne of Destruction - WorldStone Keep Level 3 Added by Darien +} + +/* +function main() { + buildTileList(); + if (me.area==2) { + clickme=getTile(8); // 8 is the area I want to be in + tileInteract(clickme); + } +} +*/ + +function getTile(n) { + var oldarea=me.area; + var tile=getUnit(5); + if(tile) do { + + if(tile.classid==tilelist[me.area][n]) { + print(tile.name); + print("Tile " + tile.classid + " at "+tile.x+ ", "+tile.y); + return tile; + } + } while (tile.getNext()); + return false; +} + +function tileInteract(o) { + //mlwalkto(o.x, o.y); + var oldarea=me.area; + delay(100); + o.move(); + delay(100); + me.move(o.x, o.y); + delay(100); + o.interact(); + var intercount=0; + while (me.area==oldarea && intercount < 20) { + o.interact(); + delay(100); + intercount++; + } + if(me.area == oldarea) print("Failed to interact with tile"); +} diff --git a/d2bs/kolbot/sdk/uiflag.txt b/d2bs/kolbot/sdk/uiflag.txt new file mode 100644 index 000000000..ad50b3b1d --- /dev/null +++ b/d2bs/kolbot/sdk/uiflag.txt @@ -0,0 +1,37 @@ +0x01 Inventory open +0x02 Character Stat screen open +0x03 quick skill +0x04 skill +0x05 Chat box open (typing something) +0x06 +0x07 +0x08 npc menu +0x09 Esc menu? +0x0A Automap is on +0x0B config controls +0x0C Shop open at NPC +0x0D alt show items +0x0E cash +0x0F quest +0x10 +0x11 questlog button +0x12 status area +0x13 ? +0x14 waypoint +0x15 mini panel +0x16 party +0x17 Trade Prompt up [ok/cancel] (player) or in Trade w/player +0x18 msgs +0x19 Stash is open +0x1A Cube is open +0x1B +0x1C +0x1D +0x1E +0x1F Belt show all is toggled +0x20 +0x21 help +0x22 +0x23 +0x24 Merc screen +0x25 scroll of whatever diff --git a/d2bs/kolbot/sdk/waypoints.txt b/d2bs/kolbot/sdk/waypoints.txt new file mode 100644 index 000000000..a9b726b74 --- /dev/null +++ b/d2bs/kolbot/sdk/waypoints.txt @@ -0,0 +1 @@ +var waypoints = [[0x01,0x03,0x04,0x05,0x06,0x1b,0x1d,0x20,0x23],[0x28,0x30,0x2a,0x39,0x2b,0x2c,0x34,0x4a,0x2e],[0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x53,0x65],[0x67,0x6a,0x6b],[0x6d,0x6f,0x70,0x71,0x73,0x7b,0x75,0x76,0x81]]; diff --git a/d2bs/kolbot/tools/AntiHostile.js b/d2bs/kolbot/tools/AntiHostile.js index 3a9f3e975..b724a4193 100644 --- a/d2bs/kolbot/tools/AntiHostile.js +++ b/d2bs/kolbot/tools/AntiHostile.js @@ -4,34 +4,50 @@ * @desc handle hostile threats */ -function main() { - // Include libraries - include("json2.js"); - include("NTItemParser.dbl"); - include("OOG.js"); - include("Gambling.js"); - include("common/Attack.js"); - include("common/Cubing.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"); +js_strict(true); + +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"); +include("common/CollMap.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"); +include("common/Enums.js"); +function main() { // Variables and functions - var i, player, findTrigger, attackCount, - hostiles = [], - prevPos = {}; - - // Filps the 'find' trigger - allows the main loop to scan for hostiles - this.hostileEvent = function (mode, param1, param2, name1, name2) { - if (mode === 7 && param2 === 3) { - findTrigger = true; + 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 "remove": // Remove a hostile player that left the game + if (hostiles.indexOf(msg.split(" ")[1]) > -1) { + hostiles.splice(hostiles.indexOf(msg.split(" ")[1]), 1); + } + + break; + case "mugshot": // Take a screenshot and log the kill + D2Bot.printToConsole(msg.split(" ")[1] + " has been neutralized.", 4); + hideConsole(); + delay(500); + takeScreenshot(); + + break; } }; @@ -42,7 +58,7 @@ function main() { if (party) { do { if (party.name !== me.name && getPlayerFlag(me.gid, party.gid, 8) && hostiles.indexOf(party.name) === -1) { - D2Bot.printToConsole(party.name + " has declared hostility.;6"); + D2Bot.printToConsole(party.name + " (Level " + party.level + " " + charClass[party.classid] + ")" + " has declared hostility.", 8); hostiles.push(party.name); } } while (party.getNext()); @@ -52,115 +68,307 @@ function main() { }; // Pause default so actions don't conflict - this.togglePause = function () { + this.pause = function () { var script = getScript("default.dbj"); - if (script) { - if (script.running) { - print("ÿc1Pausing."); - script.pause(); - } else { - print("ÿc2Resuming."); - script.resume(); + if (script && script.running) { + print("ÿc1Pausing."); + script.pause(); + } + }; + + // Resume default + this.resume = function () { + var script = getScript("default.dbj"); + + if (script && !script.running) { + print("ÿc2Resuming."); + script.resume(); + } + }; + + // Find hostile player Units + this.findPlayer = function () { + var i, player; + + for (i = 0; i < hostiles.length; i += 1) { + player = getUnit(UnitType.Player, hostiles[i]); + + if (player) { + do { + if (player.mode !== PlayerModes.Death && player.mode !== PlayerModes.Dead && getPlayerFlag(me.gid, player.gid, 8) && !player.inTown && !me.inTown) { + return player; + } + } while (player.getNext()); + } + } + + return false; + }; + + // Find a missile type + this.findMissile = function (owner, id, range) { + if (range === undefined) { + range = 999; + } + + var missile = getUnit(UnitType.Missile, id); + + if (!missile) { + return false; + } + + do { + if (missile.owner === owner.gid && getDistance(owner, missile) < range) { + return missile; } + } while (missile.getNext()); + + return false; + }; + + this.checkSummons = function (player) { + var unit, + name = player.name; + + unit = getUnit(UnitType.NPC); + + if (unit) { + do { + // Revives and spirit wolves + if (unit.getParent() && unit.getParent().name === name && (unit.getState(States.REVIVE) || unit.classid === UnitClassID.spiritwolf)) { + return true; + } + } while (unit.getNext()); } + + return false; }; // Init config and attacks + D2Bot.init(); Config.init(); Attack.init(); Storage.Init(); - // Attack sequence adjustments - switch (me.classid) { - case 1: // Sorceress - increase skill range - if ([47, 49, 53, 56, 59].indexOf(Config.AttackSkill[1]) > -1) { - ClassAttack.skillRange[1] = 40; - ClassAttack.skillRange[2] = 40; - } + // Use PVP range for attacks + Skill.usePvpRange = true; - 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 + // Attack sequence adjustments - this only affects the AntiHostile thread + switch (me.classid) { + case ClassID.Assassin: // Assassin - use Mind Blast with trapsins + if (me.getSkill(Skills.Assassin.Mind_Blast, 1) && [Skills.Assassin.Fire_Trauma, Skills.Assassin.Shock_Field].indexOf(Config.AttackSkill[1]) > -1) { + Config.AttackSkill[1] = Skills.Assassin.Mind_Blast; // Mind Blast + ClassAttack.trapRange = 40; } break; } - addEventListener("gameevent", this.hostileEvent); + // A simple but fast player dodge function + this.moveAway = function (unit, range) { + var i, coordx, coordy, + 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]; + + for (i = 0; i < angles.length; i += 1) { + // Avoid the position where the player actually tries to move to + coordx = Math.round((Math.cos((angle + angles[i]) * Math.PI / 180)) * range + unit.x); // unit.targetx + coordy = Math.round((Math.sin((angle + angles[i]) * Math.PI / 180)) * range + unit.y); // unit.targety + + if (Attack.validSpot(coordx, coordy)) { + return Pather.moveTo(coordx, coordy); + } + } + + return false; + }; + + addEventListener("scriptmsg", this.scriptEvent); print("ÿc2Anti-Hostile thread loaded."); - this.findHostiles(); // Main Loop while (true) { - // Scan for hostiles or quit - if (findTrigger) { - if (Config.HostileAction === 0) { - quit(); + if (me.gameReady) { + // Scan for hostiles + this.findHostiles(); + + if (hostiles.length > 0 && (Config.HostileAction === 0 || (Config.HostileAction === 1 && me.inTown))) { + if (Config.TownOnHostile) { + this.pause(); + Town.goToTown(); + + while (hostiles.length > 0) { + delay(500); + } + + Pather.usePortal(null, me.name); + this.resume(); + } else { + scriptBroadcast("quit"); + } + + return; } - this.findHostiles(); + // Mode 3 - Spam entrance (still experimental) + if (Config.HostileAction === 3 && hostiles.length > 0 && me.area === Areas.Act5.Throne_Of_Destruction) { + switch (me.classid) { + case ClassID.Sorceress: // Sorceress + prevPos = {x: me.x, y: me.y}; + this.pause(); + Pather.moveTo(15103, 5247); Skills.Druid.Tornado - findTrigger = false; - } + while (!this.findPlayer() && hostiles.length > 0) { + if (!me.getState(States.SKILLDELAY)) { + Skill.cast(Config.AttackSkill[1], Skill.getHand(Config.AttackSkill[1]), 15099, 5237); + } else { + if (Config.AttackSkill[2] > -1) { + Skill.cast(Config.AttackSkill[2], Skill.getHand(Config.AttackSkill[2]), 15099, 5237); + } else { + while (me.getState(States.SKILLDELAY)) { + delay(40); + } + } + } + } - for (i = 0; i < hostiles.length; i += 1) { - player = getUnit(0, hostiles[i]); + break; + case ClassID.Druid: // Druid + // Don't bother if it's not a tornado druid + if (Config.AttackSkill[1] !== 245) { + break; + } + + prevPos = {x: me.x, y: me.y}; + this.pause(); + Pather.moveTo(15103, 5247); + + 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], Skill.getHand(Config.AttackSkill[1]), 15099 + rand(-2, 2), 5237); + } + + break; + case ClassID.Assassin: // Assassin + prevPos = {x: me.x, y: me.y}; + this.pause(); + Pather.moveTo(15103, 5247); + + while (!this.findPlayer() && hostiles.length > 0) { + if (Config.UseTraps) { + check = ClassAttack.checkTraps({ x: 15099, y: 5242, classid: UnitClassID.baalcrab}); + + if (check) { + ClassAttack.placeTraps({ x: 15099, y: 5242, classid: UnitClassID.baalcrab}, 5); + } + } + + Skill.cast(Config.AttackSkill[1], Skill.getHand(Config.AttackSkill[1]), 15099, 5237); + + while (me.getState(States.SKILLDELAY)) { + delay(40); + } + } + + break; + } + } + + // Player left, return to old position + if (!hostiles.length && prevPos) { + Pather.moveTo(prevPos.x, prevPos.y); + this.resume(); + + // Reset position + prevPos = false; + } + + player = this.findPlayer(); if (player) { - do { - if (player.mode !== 0 && player.mode !== 17 && getPlayerFlag(me.gid, player.gid, 8) && !player.inTown) { - // Quit if hostile player is nearby - if (Config.HostileAction === 1) { - quit(); + // Mode 1 - Quit if hostile player is nearby + if (Config.HostileAction === 1) { + if (Config.TownOnHostile) { + this.pause(); + Town.goToTown(); + + while (hostiles.length > 0) { + delay(500); } - // Kill the hostile player - prevPos = {x: me.x, y: me.y}; + Pather.usePortal(null, me.name); + this.resume(); + } else { + scriptBroadcast("quit"); + } - this.togglePause(); + return; + } - Config.UseMerc = false; // Don't go revive the merc mid-fight - attackCount = 0; + // Kill the hostile player + if (!prevPos) { + prevPos = {x: me.x, y: me.y}; + } - while (attackCount < 100) { - if (!copyUnit(player).x) { // Invalidated unit (out of getUnit range) - break; - } + this.pause(); - switch (me.classid) { - case 1: // Sorceress - if (ClassAttack.skillRange[1] > 20 && getDistance(me, player) < 30) { - print(ClassAttack.skillRange[1]); + Config.UseMerc = false; // Don't go revive the merc mid-fight + attackCount = 0; - Attack.getIntoPosition(player, ClassAttack.skillRange[1], 0x4); - } + while (attackCount < 100) { + if (!copyUnit(player).x || player.inTown || me.mode === PlayerModes.Dead) { // Invalidated Unit (out of getUnit range) or player in town + break; + } - break; - } + ClassAttack.doAttack(player, false); - ClassAttack.doAttack(player, false); + // Specific attack additions + switch (me.classid) { + case ClassID.Sorceress: // Sorceress + case ClassID.Necromancer: // Necromancer + // Dodge missiles - experimental + missile = getUnit(UnitType.Missile); - attackCount += 1; + 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, Skill.getRange(Config.AttackSkill[1])); + + break; + } + } while (missile.getNext()); + } - if (player.mode === 0 || player.mode === 17) { - D2Bot.printToConsole(player.name + " has been neutralized.;3"); - hideConsole(); - delay(500); - takeScreenshot(); + // Move away if the player is too close or if he tries to move too close (telestomp) + 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; + break; + case ClassID.Paladin: // Paladin + // Smite summoners + if (Config.AttackSkill[1] === Skills.Paladin.Blessed_Hammer && me.getSkill(Skills.Paladin.Smite, 1)) { + if ([ClassID.Necromancer, ClassID.Druid].indexOf(player.classid) > -1 && getDistance(me, player) < 4 && this.checkSummons(player)) { + Skill.cast(Skills.Paladin.Smite, 1, player); } } - Pather.moveTo(prevPos.x, prevPos.y); - this.togglePause(); + break; + } + + attackCount += 1; + + if (player.mode === PlayerModes.Death || player.mode === PlayerModes.Dead) { + break; } - } while (player.getNext()); // cycle through eventual corpses + } + + Pather.moveTo(prevPos.x, prevPos.y); + this.resume(); } } - delay(500); + delay(200); } } \ No newline at end of file diff --git a/d2bs/kolbot/tools/AutoBuildThread.js b/d2bs/kolbot/tools/AutoBuildThread.js new file mode 100644 index 000000000..25cc53d16 --- /dev/null +++ b/d2bs/kolbot/tools/AutoBuildThread.js @@ -0,0 +1,266 @@ +/** +* @title : AutoBuildThread.js +* +* @author : alogwe +* +* @desc : A script that will automatically allocate skill and stat points based on a configurable +* character build table. Point spending occurs on level up. Additional skill and stat points +* rewarded by quests are currently not used by this script. +*/ + +js_strict(true); + +if (!isIncluded("common/Config.js")) { include("common/Config.js"); }; +if (!isIncluded("common/Cubing.js")) { include("common/Cubing.js"); }; +if (!isIncluded("common/Prototypes.js")) { include("common/Prototypes.js"); }; +if (!isIncluded("common/Runewords.js")) { include("common/Runewords.js"); }; +if (!isIncluded("common/Enums.js")) { include("common/Enums.js"); }; + +Config.init(); // includes libs/common/AutoBuild.js + +var debug = !!Config.AutoBuild.DebugMode; +var prevLevel = me.charlvl; +const SPEND_POINTS = true; // For testing, it actually allows skill and stat point spending. +const STAT_ID_TO_NAME = [getLocaleString(4060), // Strength + getLocaleString(4069), // Energy + getLocaleString(4062), // Dexterity + getLocaleString(4066)]; // Vitality + + +// Will check if value exists in an Array +Array.prototype.contains = function (val) { return this.indexOf(val) > -1; }; + + +function skillInValidRange (id) { + switch (me.classid) { + case ClassID.Amazon: return Skills.Amazon.Magic_Arrow <= id && id <= Skills.Amazon.Lightning_Fury; // Amazon + case ClassID.Sorceress: return Skills.Sorceress.Fire_Bolt <= id && id <= Skills.Sorceress.Cold_Mastery; // Sorceress + case ClassID.Necromancer: return Skills.Necromancer.Amplify_Damage <= id && id <= Skills.Necromancer.Revive; // Necromancer + case ClassID.Paladin: return Skills.Paladin.Sacrifice <= id && id <= Skills.Paladin.Salvation; // Paladin + case ClassID.Barbarian: return Skills.Barbarian.Bash <= id && id <= Skills.Barbarian.Battle_Command; // Barbarian + case ClassID.Druid: return Skills.Druid.Raven <= id && id <= Skills.Druid.Hurricane; // Druid + case ClassID.Assassin: return Skills.Assassin.Fire_Trauma <= id && id <= Skills.Assassin.Royal_Strike; // Assassin + default: + } + return false; +}; + + +function gainedLevels () { return me.charlvl - prevLevel; }; + + +function canSpendPoints () { + var unusedStatPoints = me.getStat(Stats.statpts); + var haveUnusedStatpoints = unusedStatPoints >= 5; // We spend 5 stat points per level up + var unusedSkillPoints = me.getStat(Stats.newskills); + var haveUnusedSkillpoints = unusedSkillPoints >= 1; // We spend 1 skill point per level up + if (debug) { AutoBuild.print("Stat points:", unusedStatPoints, " Skill points:", unusedSkillPoints); } + return haveUnusedStatpoints && haveUnusedSkillpoints; +}; + + +function spendStatPoint (id) { + var unusedStatPoints = me.getStat(Stats.statpts); + if (SPEND_POINTS) { + useStatPoint(id); + AutoBuild.print("useStatPoint("+id+"): "+STAT_ID_TO_NAME[id]); + } else { + AutoBuild.print("Fake useStatPoint("+id+"): "+STAT_ID_TO_NAME[id]); + } + delay(100); // TODO: How long should we wait... if at all? + return (unusedStatPoints - me.getStat(Stats.statpts) === 1); // Check if we spent one point +}; + + +// TODO: What do we do if it fails? report/ignore/continue? +function spendStatPoints () { + var stats = AutoBuildTemplate[me.charlvl].StatPoints; + var errorMessage = "\nInvalid stat point set in build template "+getTemplateFilename()+" at level "+me.charlvl; + var spentEveryPoint = true; + var unusedStatPoints = me.getStat(Stats.statpts); + var len = stats.length; + + if (len > unusedStatPoints) { + len = unusedStatPoints; + AutoBuild.print("Warning: Number of stats specified in your build template at level "+me.charlvl+" exceeds the available unused stat points"+ + "\nOnly the first "+len+" stats "+stats.slice(0, len).join(", ")+" will be added"); + } + + // We silently ignore stats set to -1 + for (var i = 0; i < len; i++) { + var id = stats[i]; + var statIsValid = (typeof id === "number") && (Stats.strength <= id && id <= Stats.vitality); + + if (id === -1) { continue; } + else if (statIsValid) { + var preStatValue = me.getStat(id); + var pointSpent = spendStatPoint(id); + if (SPEND_POINTS) { + if (!pointSpent) { + spentEveryPoint = false; + AutoBuild.print("Attempt to spend point "+(i+1)+" in "+STAT_ID_TO_NAME[id]+" may have failed!"); + } else if (debug) { + AutoBuild.print("Stat ("+(i+1)+"/"+len+") Increased "+STAT_ID_TO_NAME[id]+" from "+preStatValue+" to "+me.getStat(id)); + } + } + } else { + throw new Error("Stat id must be one of the following:\n0:"+STAT_ID_TO_NAME[0] + + ",\t1:"+STAT_ID_TO_NAME[1]+",\t2:"+STAT_ID_TO_NAME[2]+",\t3:"+STAT_ID_TO_NAME[3] + errorMessage); + } + } + + return spentEveryPoint; +}; + + +function getTemplateFilename () { + var classname = ["Amazon", "Sorceress", "Necromancer", "Paladin", "Barbarian", "Druid", "Assassin"][me.classid]; + var buildType = Config.AutoBuild.Template; + var templateFilename = "config/Builds/"+classname+"."+buildType+".js"; + return templateFilename; +}; + + +function getRequiredSkills (id) { + + function searchSkillTree (id) { + var results = []; + var skillTreeRight = getBaseStat("skills", id, 181); + var skillTreeMiddle = getBaseStat("skills", id, 182); + var skillTreeLeft = getBaseStat("skills", id, 183); + + results.push(skillTreeRight); + results.push(skillTreeMiddle); + results.push(skillTreeLeft); + + for (var i = 0; i < results.length; i++) { + var skill = results[i]; + var skillInValidRange = (0 < skill && skill <= 280) && (![Skills.common.Scroll_of_Identify, Skills.common.Book_of_Identify, Skills.common.Scroll_of_Townportal, Skills.common.Book_of_Townportal].contains(skill)); + var hardPointsInSkill = me.getSkill(skill, 0); + + if (skillInValidRange && !hardPointsInSkill) { + requirements.push(skill); + searchSkillTree(skill); // search children; + } + } + }; + + var requirements = []; + searchSkillTree(id); + function increasing (a, b) { return a-b; }; + return requirements.sort(increasing); +}; + + +function spendSkillPoint (id) { + var unusedSkillPoints = me.getStat(Stats.newskills); + var skillName = getSkillById(id)+" ("+id+")"; // TODO: Use let ? + if (SPEND_POINTS) { + useSkillPoint(id); + AutoBuild.print("useSkillPoint(): "+skillName); + } else { + AutoBuild.print("Fake useSkillPoint(): "+skillName); + } + delay(200); // TODO: How long should we wait... if at all? + return (unusedSkillPoints - me.getStat(Stats.newskills) === 1); // Check if we spent one point +}; + + +function spendSkillPoints () { + var skills = AutoBuildTemplate[me.charlvl].SkillPoints; + var errInvalidSkill = "\nInvalid skill point set in build template "+getTemplateFilename()+" for level "+me.charlvl; + var spentEveryPoint = true; + var unusedSkillPoints = me.getStat(Stats.newskills); + var len = skills.length; + + if (len > unusedSkillPoints) { + len = unusedSkillPoints; + AutoBuild.print("Warning: Number of skills specified in your build template at level "+me.charlvl+" exceeds the available unused skill points"+ + "\nOnly the first "+len+" skills "+skills.slice(0, len).join(", ")+" will be added"); + } + + // We silently ignore skills set to -1 + for (var i = 0; i < len; i++) { + var id = skills[i]; // TODO: Use let ? + + if (id === -1) { continue; } + else if (!skillInValidRange(id)) { + throw new Error("Skill id "+id+" is not a skill for your character class"+errInvalidSkill); + } + + var skillName = getSkillById(id)+" ("+id+")"; // TODO: Use let ? + var requiredSkills = getRequiredSkills(id); + if (requiredSkills.length > 0) { + throw new Error("You need prerequisite skills "+requiredSkills.join(", ")+" before adding "+skillName+errInvalidSkill); + } + + var requiredLevel = getBaseStat("skills", id, 176); + if (me.charlvl < requiredLevel) { + throw new Error("You need to be at least level "+requiredLevel+" before you get "+skillName+errInvalidSkill); + } + + var pointSpent = spendSkillPoint(id); + + if (SPEND_POINTS) { + if (!pointSpent) { + spentEveryPoint = false; + AutoBuild.print("Attempt to spend skill point "+(i+1)+" in "+skillName+" may have failed!"); + } else if (debug) { + var actualSkillLevel = me.getSkill(id, 1); + AutoBuild.print("Skill ("+(i+1)+"/"+len+") Increased "+skillName+" by one (level: ", actualSkillLevel+")"); + } + } + + delay(200); // TODO: How long should we wait... if at all? + } + + return spentEveryPoint; +}; + + + +/* +* TODO: determine if changes need to be made for +* the case of gaining multiple levels at once so as +* not to bombard the d2bs event system +*/ + +function main () { + try { + AutoBuild.print("Loaded helper thread"); + + while (true) { + var levels = gainedLevels(); + + if (levels > 0 && canSpendPoints()) { + scriptBroadcast("toggleQuitlist"); + AutoBuild.print("Level up detected (", prevLevel, "-->", me.charlvl, ")"); + spendSkillPoints(); + spendStatPoints(); + scriptBroadcast({event: "level up"}); + AutoBuild.applyConfigUpdates(); // scriptBroadcast() won't trigger listener on this thread. + + if (debug) { + AutoBuild.print("Incrementing cached character level to", prevLevel + 1); + } + + // prevLevel doesn't get set to me.charlvl because + // we may have gained multiple levels at once + prevLevel += 1; + + scriptBroadcast("toggleQuitlist"); + } + + delay(1e3); + } + } catch (err) { + print("Something broke!"); + print("Error:"+ err.toSource()); + print("Stack trace: \n"+ err.stack); + return false; + } + + return true; +}; + + diff --git a/d2bs/kolbot/tools/CloneKilla.js b/d2bs/kolbot/tools/CloneKilla.js new file mode 100644 index 000000000..e28763792 --- /dev/null +++ b/d2bs/kolbot/tools/CloneKilla.js @@ -0,0 +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("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/HeartBeat.js b/d2bs/kolbot/tools/HeartBeat.js new file mode 100644 index 000000000..5b2421a68 --- /dev/null +++ b/d2bs/kolbot/tools/HeartBeat.js @@ -0,0 +1,54 @@ +/** +* @filename HeartBeat.js +* @author kolton +* @desc Keep a link with d2bot#. If it's lost, the d2 window is killed +*/ + +function main() { + include("oog.js"); + include("json2.js"); + include("common/misc.js"); + D2Bot.init(); + print("Heartbeat loaded"); + + function togglePause() { + var script = getScript(); + + if (script) { + do { + 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 true; + } + + // Event functions + function KeyEvent(key) { + switch (key) { + case 19: + if (me.ingame) { + break; + } + + togglePause(); + + break; + } + } + + addEventListener("keyup", KeyEvent); + + while (true) { + D2Bot.heartBeat(); + delay(1000); + } +} \ No newline at end of file diff --git a/d2bs/kolbot/tools/MapHelper.js b/d2bs/kolbot/tools/MapHelper.js new file mode 100644 index 000000000..09d15d97f --- /dev/null +++ b/d2bs/kolbot/tools/MapHelper.js @@ -0,0 +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, 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 new file mode 100644 index 000000000..283409420 --- /dev/null +++ b/d2bs/kolbot/tools/MapThread.js @@ -0,0 +1,772 @@ +include("common/Enums.js"); + +var Hooks = { + monsters: { + hooks: [], + enabled: true, + + check: function () { + if (!this.enabled) { + this.flush(); + + return; + } + + var i, unit; + + for (i = 0; i < this.hooks.length; i += 1) { + if (!copyUnit(this.hooks[i].unit).x) { + this.hooks[i].hook[0].remove(); + this.hooks[i].hook[1].remove(); + this.hooks.splice(i, 1); + + i -= 1; + } + } + + unit = getUnit(1); + + if (unit) { + do { + if (Attack.checkMonster(unit)) { + if (!this.getHook(unit)) { + this.add(unit); + } else { + this.updateCoords(unit); + } + } else { + this.remove(unit); + } + } while (unit.getNext()); + } + }, + + newHook: function (unit) { + var arr = []; + + arr.push(new Line(unit.x - 5, unit.y, unit.x + 5, unit.y, (unit.spectype & 0xF) ? 0x68 : 0x62, true)); + arr.push(new Line(unit.x, unit.y - 5, unit.x, unit.y + 5, (unit.spectype & 0xF) ? 0x68 : 0x62, true)); + + return arr; + }, + + add: function (unit) { + this.hooks.push({ + unit: copyUnit(unit), + hook: this.newHook(unit) + }); + }, + + updateCoords: function (unit) { + var hook = this.getHook(unit); + + if (!hook) { + return false; + } + + hook[0].x = unit.x - 5; + hook[0].x2 = unit.x + 5; + hook[0].y = unit.y; + hook[0].y2 = unit.y; + hook[1].x = unit.x; + hook[1].x2 = unit.x; + hook[1].y = unit.y - 5; + hook[1].y2 = unit.y + 5; + + return true; + }, + + getHook: function (unit) { + var i; + + for (i = 0; i < this.hooks.length; i += 1) { + if (this.hooks[i].unit.gid === unit.gid) { + return this.hooks[i].hook; + } + } + + return false; + }, + + remove: function (unit) { + var i; + + for (i = 0; i < this.hooks.length; i += 1) { + if (this.hooks[i].unit.gid === unit.gid) { + this.hooks[i].hook[0].remove(); + this.hooks[i].hook[1].remove(); + this.hooks.splice(i, 1); + + return true; + } + } + + return false; + }, + + flush: function () { + while (this.hooks.length) { + this.hooks[0].hook[0].remove(); + this.hooks[0].hook[1].remove(); + this.hooks.shift(); + } + } + }, + + text: { + hooks: [], + enabled: true, + + check: function () { + if (!this.enabled) { + this.flush(); + + return; + } + + if (!this.getHook("monsterStatus")) { + this.add("monsterStatus"); + } + + if (!this.getHook("vectorStatus")) { + this.add("vectorStatus"); + } + + if (!this.getHook("ping")) { + this.add("ping"); + } else { + this.getHook("ping").hook.text = "Ping: " + me.ping; + } + + if (!this.getHook("time")) { + this.add("time"); + } else { + this.getHook("time").hook.text = this.timer(); + } + + if (!this.getHook("ip")) { + this.add("ip"); + } + }, + + add: function (name) { + switch (name) { + case "ping": + this.hooks.push({ + name: "ping", + hook: new Text("Ping: " + me.ping, 785, 56 + 16 * (Number(!!me.diff) + Number(!!me.gamepassword) + Number(!!me.gametype) + Number(!!me.gamename)), 4, 1, 1) + }); + + break; + case "time": + this.hooks.push({ + name: "time", + hook: new Text(this.timer(), 785, 72 + 16 * (Number(!!me.diff) + Number(!!me.gamepassword) + Number(!!me.gametype) + Number(!!me.gamename)), 4, 1, 1) + }); + + break; + case "ip": + this.hooks.push({ + name: "ip", + hook: new Text("IP: " + (me.gameserverip.length > 0 ? me.gameserverip.split(".")[3] : "0"), 785, 88 + 16 * (Number(!!me.diff) + Number(!!me.gamepassword) + Number(!!me.gametype) + Number(!!me.gamename)), 4, 1, 1) + }); + + break; + case "monsterStatus": + this.hooks.push({ + name: "monsterStatus", + hook: new Text("Num 7: Disable Monsters", 525, 515) + }); + + break; + case "vectorStatus": + this.hooks.push({ + name: "vectorStatus", + hook: new Text("Num 8: Disable Vectors", 525, 525) + }); + + break; + } + }, + + getHook: function (name) { + var i; + + for (i = 0; i < this.hooks.length; i += 1) { + if (this.hooks[i].name === name) { + return this.hooks[i]; + } + } + + return false; + }, + + timer: function () { + var min, sec; + + min = Math.floor((getTickCount() - me.gamestarttime) / 60000).toString(); + + if (min <= 9) { + min = "0" + min; + } + + sec = (Math.floor((getTickCount() - me.gamestarttime) / 1000) % 60).toString(); + + if (sec <= 9) { + sec = "0" + sec; + } + + return min + ":" + sec; + }, + + flush: function () { + if (getUIFlag(UIFlags.alt_show_items)) { + return; + } + + while (this.hooks.length) { + this.hooks.shift().hook.remove(); + } + } + }, + + vector: { + hooks: [], + currArea: 0, + enabled: true, + + check: function () { + if (!this.enabled) { + this.flush(); + + return; + } + + if (me.area !== this.currArea) { + this.flush(); + + var i, exits, wp, poi; + + this.currArea = me.area; + exits = getArea().exits; + + if (exits) { + for (i = 0; i < exits.length; i += 1) { + this.add(exits[i].x, exits[i].y, me.area === Areas.Act2.Canyon_Of_The_Magi && exits[i].target === getRoom().correcttomb ? 0x69 : 0x99); + } + } + + wp = this.getWP(); + + if (wp) { + this.add(wp.x, wp.y, 0xA8); + } + + poi = this.getPOI(); + + if (poi) { + this.add(poi.x, poi.y, 0x7D); + } + } else { + this.update(); + } + }, + + add: function (x, y, color) { + this.hooks.push(new Line(me.x, me.y, x, y, color, true)); + }, + + update: function () { + var i; + + for (i = 0; i < this.hooks.length; i += 1) { + this.hooks[i].x = me.x; + this.hooks[i].y = me.y; + } + }, + + flush: function () { + while (this.hooks.length) { + this.hooks.shift().remove(); + } + + this.currArea = 0; + }, + + getWP: function () { + if (Pather.wpAreas.indexOf(me.area) === -1) { + return false; + } + + var i, preset, + wpIDs = [119, 145, 156, 157, 237, 238, 288, 323, 324, 398, 402, 429, 494, 496, 511, 539]; + + for (i = 0; i < wpIDs.length; i += 1) { + preset = getPresetUnit(me.area, UnitType.Object, wpIDs[i]); + + if (preset) { + return { + x: preset.roomx * 5 + preset.x, + y: preset.roomy * 5 + preset.y + }; + } + } + + return false; + }, + + getPOI: function () { + var unit, name; + + switch (me.area) { + case Areas.Act1.Stony_Field: // Stony Field + unit = getPresetUnit(me.area, UnitType.NPC, SuperUniques.Rakanishu); + name = "Cairn Stones"; + + break; + case Areas.Act1.Dark_Wood: // Dark Wood + unit = getPresetUnit(me.area, UnitType.Object, UniqueObjectIds.Inifuss_Tree); + name = "Tree"; + + break; + case Areas.Act2.A2_Sewers_Level_3: // Sewers 3 + unit = getPresetUnit(me.area, UnitType.Object, UniqueObjectIds.Horadric_Scroll_Chest); + name = "Radament"; + + break; + case Areas.Act2.Halls_Of_The_Dead_Level_3: // Halls of the Dead 3 + unit = getPresetUnit(me.area, UnitType.Object, UniqueObjectIds.Horadric_Cube_Chest); + name = "Cube"; + + break; + case Areas.Act2.Arcane_Sanctuary: // Arcane Sanctuary + unit = getPresetUnit(me.area, UnitType.Object, UniqueObjectIds.Horazons_Journal); + name = "Summoner"; + + break; + case Areas.Act2.Maggot_Lair_Level_3: // Maggot Lair 3 + unit = getPresetUnit(me.area, UnitType.NPC, SuperUniques.Coldworm_the_Burrower); + name = "Fat Worm"; + + break; + case Areas.Act2.Tal_Rashas_Tomb_1: // Tal Rasha's Tombs + case Areas.Act2.Tal_Rashas_Tomb_2: + case Areas.Act2.Tal_Rashas_Tomb_3: + case Areas.Act2.Tal_Rashas_Tomb_4: + case Areas.Act2.Tal_Rashas_Tomb_5: + case Areas.Act2.Tal_Rashas_Tomb_6: + case Areas.Act2.Tal_Rashas_Tomb_7: + unit = getPresetUnit(me.area, UnitType.Object, UniqueObjectIds.Holder_For_Horadric_Staff); + name = "Orifice"; + + break; + case Areas.Act3.Flayer_Jungle: // Flayer Jungle + unit = getPresetUnit(me.area, UnitType.Object, UniqueObjectIds.Gidbinn_Decoy); + name = "Gidbinn"; + + break; + case Areas.Act3.Durance_Of_Hate_Level_3: // Durance of Hate 3 + unit = { + x: 17588, + y: 8069 + }; + name = "Mephisto"; + + break; + case Areas.Act4.Plains_Of_Despair: // Plains of Despair + unit = getPresetUnit(me.area, UnitType.NPC, UnitClassID.izual); + name = "Izual"; + + break; + case Areas.Act4.River_Of_Flame: // River of Flame + unit = getPresetUnit(me.area, UnitType.Object, UniqueObjectIds.Forge_Hell); + name = "Hephasto"; + + break; + case Areas.Act4.Chaos_Sanctuary: // Chaos Sanctuary + unit = getPresetUnit(me.area, UnitType.Object, UniqueObjectIds.Diablo_Start_Point); + name = "Star"; + + break; + case Areas.Act5.Frigid_Highlands: // Frigid Highlands + case Areas.Act5.Arreat_Plateau: // Arreat Plateau + case Areas.Act5.Frozen_Tundra: // Frozen Tundra + unit = getPresetUnit(me.area, UnitType.Object, UniqueObjectIds.Permanent_Town_Portal); + name = "Hell Entrance"; + + break; + case Areas.Act5.Halls_Of_Vaught: // Halls of Vaught + unit = getPresetUnit(me.area, UnitType.Object, UniqueObjectIds.Nihlathak_Outside_Town); + name = "Nihlathak"; + + break; + } + + if (unit) { + if (unit instanceof PresetUnit) { + return { + x: unit.roomx * 5 + unit.x, + y: unit.roomy * 5 + unit.y, + name: name + }; + } + + return { + x: unit.x, + y: unit.y, + name: name + }; + } + + return false; + } + }, + + tele: { + hooks: [], + action: null, + currArea: Areas.None, + enabled: true, + prevAreas: [Areas.None, Areas.None, Areas.Act1.Rogue_Encampment, Areas.Act1.Blood_Moor, Areas.Act1.Cold_Plains, Areas.Act1.Underground_Passage_Level_1, Areas.Act1.Dark_Wood, + Areas.Act1.Black_Marsh, Areas.Act1.Blood_Moor, Areas.Act1.Cold_Plains, Areas.Act1.Stony_Field, Areas.Act1.Black_Marsh, Areas.Act1.Tamoe_Highland, Areas.Act1.Cave_Level_1, + Areas.Act1.Underground_Passage_Level_1, Areas.Act1.Hole_Level_1, Areas.Act1.Pit_Level_1, Areas.Act1.Cold_Plains, Areas.Act1.Burial_Grounds, Areas.Act1.Burial_Grounds, + Areas.Act1.Black_Marsh, Areas.Act1.Forgotten_Tower, Areas.Act1.Tower_Cellar_Level_1, Areas.Act1.Tower_Cellar_Level_2, Areas.Act1.Tower_Cellar_Level_3, Areas.Act1.Tower_Cellar_Level_4, + Areas.Act1.Tamoe_Highland, Areas.Act1.Monastery_Gate, Areas.Act1.Outer_Cloister, Areas.Act1.Barracks, Areas.Act1.Jail_Level_1, Areas.Act1.Jail_Level_2, Areas.Act1.Jail_Level_3, + Areas.Act1.Inner_Cloister, Areas.Act1.Cathedral, Areas.Act1.Catacombs_Level_1, Areas.Act1.Catacombs_Level_2, Areas.Act1.Catacombs_Level_3, Areas.Act1.Stony_Field, + Areas.Act1.Rogue_Encampment, Areas.Act1.Rogue_Encampment, Areas.Act2.Lut_Gholein, Areas.Act2.Rocky_Waste, Areas.Act2.Dry_Hills, Areas.Act2.Far_Oasis, Areas.Act2.Lost_City, + Areas.Act2.Arcane_Sanctuary, Areas.Act2.Lut_Gholein, Areas.Act2.A2_Sewers_Level_1, Areas.Act2.A2_Sewers_Level_2, Areas.Act2.Lut_Gholein, Areas.Act2.Harem_Level_1, + Areas.Act2.Harem_Level_2, Areas.Act2.Palace_Cellar_Level_1, Areas.Act2.Palace_Cellar_Level_2, Areas.Act2.Rocky_Waste, Areas.Act2.Dry_Hills, Areas.Act2.Halls_Of_The_Dead_Level_1, + Areas.Act2.Valley_Of_Snakes, Areas.Act2.Stony_Tomb_Level_1, Areas.Act2.Halls_Of_The_Dead_Level_2, Areas.Act2.Claw_Viper_Temple_Level_1, Areas.Act2.Far_Oasis, + Areas.Act2.Maggot_Lair_Level_1, Areas.Act2.Maggot_Lair_Level_2, Areas.Act2.Lost_City, Areas.Act2.Canyon_Of_The_Magi, Areas.Act2.Canyon_Of_The_Magi, Areas.Act2.Canyon_Of_The_Magi, + Areas.Act2.Canyon_Of_The_Magi, Areas.Act2.Canyon_Of_The_Magi, Areas.Act2.Canyon_Of_The_Magi, Areas.Act2.Canyon_Of_The_Magi, Areas.Act1.Rogue_Encampment, + Areas.Act2.Palace_Cellar_Level_3, Areas.Act1.Rogue_Encampment, Areas.Act3.Kurast_Docktown, Areas.Act3.Spider_Forest, Areas.Act3.Spider_Forest, Areas.Act3.Flayer_Jungle, + Areas.Act3.Lower_Kurast, Areas.Act3.Kurast_Bazaar, Areas.Act3.Upper_Kurast, Areas.Act3.Kurast_Causeway, Areas.Act3.Spider_Forest, Areas.Act3.Spider_Forest, Areas.Act3.Flayer_Jungle, + Areas.Act3.Swampy_Pit_Level_1, Areas.Act3.Flayer_Jungle, Areas.Act3.Flayer_Dungeon_Level_1, Areas.Act3.Swampy_Pit_Level_2, Areas.Act3.Flayer_Dungeon_Level_2, Areas.Act3.Upper_Kurast, + Areas.Act3.A3_Sewers_Level_1, Areas.Act3.Kurast_Bazaar, Areas.Act3.Kurast_Bazaar, Areas.Act3.Upper_Kurast, Areas.Act3.Upper_Kurast, Areas.Act3.Kurast_Causeway, + Areas.Act3.Kurast_Causeway, Areas.Act3.Travincal, Areas.Act3.Durance_Of_Hate_Level_1, Areas.Act3.Durance_Of_Hate_Level_2, Areas.Act3.Durance_Of_Hate_Level_3, Areas.Act4.The_Pandemonium_Fortress, + Areas.Act4.Outer_Steppes, Areas.Act4.Plains_Of_Despair, Areas.Act4.City_Of_The_Damned, Areas.Act4.River_Of_Flame, Areas.Act4.The_Pandemonium_Fortress, Areas.Act5.Harrogath, + Areas.Act5.Bloody_Foothills, Areas.Act5.Frigid_Highlands, Areas.Act5.Arreat_Plateau, Areas.Act5.Crystalized_Passage, Areas.Act5.Crystalized_Passage, Areas.Act5.Glacial_Trail, + Areas.Act5.Glacial_Trail, Areas.Act5.Frozen_Tundra, Areas.Act5.Ancients_Way, Areas.Act5.Ancients_Way, Areas.Act5.Harrogath, Areas.Act5.Nihlathaks_Temple, Areas.Act5.Halls_Of_Anguish, + Areas.Act5.Halls_Of_Pain, Areas.Act5.Frigid_Highlands, Areas.Act5.Arreat_Plateau, Areas.Act5.Frozen_Tundra, Areas.Act5.Arreat_Summit, Areas.Act5.The_Worldstone_Keep_Level_1, + Areas.Act5.The_Worldstone_Keep_Level_2, Areas.Act5.The_Worldstone_Keep_Level_3, Areas.Act5.Throne_Of_Destruction, Areas.Act5.Harrogath, Areas.Act5.Harrogath, Areas.Act5.Harrogath, Areas.Act5.Harrogath], + + event: function (keycode) { + Hooks.tele.action = keycode; + }, + + check: function () { + if (!this.enabled) { + return; + } + + var hook, + obj = { + type: false, + dest: false + }; + + if (this.action) { + switch (this.action) { + case 96: // Numpad 0 + hook = this.getHook("Next Area"); + obj.type = "area"; + + break; + case 97: // Numpad 1 + hook = this.getHook("Previous Area"); + obj.type = "area"; + + break; + case 98: // Numpad 2 + hook = this.getHook("Waypoint"); + obj.type = "wp"; + + break; + case 99: // Numpad 3 + hook = this.getHook("POI"); + obj.type = "unit"; + + break; + case 100: // Numpad 4 + hook = this.getHook("Side Area"); + obj.type = "area"; + + break; + } + + if (hook) { + obj.dest = hook.destination; + + scriptBroadcast(JSON.stringify(obj)); + } + + this.action = null; + } + + if (me.area !== this.currArea) { + this.flush(); + this.add(me.area); + addEventListener("keyup", this.event); + + this.currArea = me.area; + } + }, + + add: function (area) { + var i, exits, wp, poi, nextCheck, + nextAreas = []; + + // Specific area override + nextAreas[7] = Areas.Act1.Monastery_Gate; + nextAreas[76] = Areas.Act3.Flayer_Jungle; + nextAreas[77] = Areas.Act3.Flayer_Jungle; + nextAreas[113] = Areas.Act5.Glacial_Trail; + nextAreas[115] = Areas.Act5.Frozen_Tundra; + nextAreas[118] = Areas.Act5.Arreat_Summit; + + if (me.area === Areas.Act2.Canyon_Of_The_Magi) { + nextAreas[46] = getRoom().correcttomb; + } + + switch (me.area) { + case Areas.Act1.Blood_Moor: // Blood Moor + this.hooks.push({ + name: "Side Area", + destination: Areas.Act1.Den_Of_Evil, + hook: new Text("Num 4: " + Pather.getAreaName(Areas.Act1.Den_Of_Evil), 150, 525 - (this.hooks.length * 10)) + }); + + break; + case Areas.Act2.Far_Oasis: // Far Oasis + this.hooks.push({ + name: "Side Area", + destination: Areas.Act2.Maggot_Lair_Level_1, + hook: new Text("Num 4: " + Pather.getAreaName(Areas.Act2.Maggot_Lair_Level_1), 150, 525 - (this.hooks.length * 10)) + }); + + break; + case Areas.Act3.Spider_Forest: + this.hooks.push({ + name: "Side Area", + destination: Areas.Act3.Spider_Cavern, + hook: new Text("Num 4: " + Pather.getAreaName(Areas.Act3.Spider_Cavern), 150, 525 - (this.hooks.length * 10)) + }); + + break; + case Areas.Act3.Flayer_Jungle: + this.hooks.push({ + name: "Side Area", + destination: Areas.Act3.Flayer_Dungeon_Level_1, + hook: new Text("Num 4: " + Pather.getAreaName(Areas.Act3.Flayer_Dungeon_Level_1), 150, 525 - (this.hooks.length * 10)) + }); + + break; + case Areas.Act3.Kurast_Bazaar: + this.hooks.push({ + name: "Side Area", + destination: Areas.Act3.Ruined_Temple, + hook: new Text("Num 4: " + Pather.getAreaName(Areas.Act3.Ruined_Temple), 150, 525 - (this.hooks.length * 10)) + }); + + break; + case Areas.Act3.Upper_Kurast: + this.hooks.push({ + name: "Side Area", + destination: Areas.Act3.A3_Sewers_Level_1, + hook: new Text("Num 4: " + Pather.getAreaName(Areas.Act3.A3_Sewers_Level_1), 150, 525 - (this.hooks.length * 10)) + }); + + break; + case Areas.Act5.Crystalized_Passage: + this.hooks.push({ + name: "Side Area", + destination: Areas.Act5.Frozen_River, + hook: new Text("Num 4: " + Pather.getAreaName(Areas.Act5.Frozen_River), 150, 525 - (this.hooks.length * 10)) + }); + + break; + } + + poi = Hooks.vector.getPOI(); + + if (poi) { + this.hooks.push({ + name: "POI", + destination: {x: poi.x, y: poi.y}, + hook: new Text("Num 3: " + poi.name, 150, 525 - (this.hooks.length * 10)) + }); + } + + wp = Hooks.vector.getWP(); + + if (wp) { + this.hooks.push({ + name: "Waypoint", + destination: {x: wp.x, y: wp.y}, + hook: new Text("Num 2: WP", 150, 525 - (this.hooks.length * 10)) + }); + } + + exits = getArea(area).exits; + + if (exits) { + for (i = 0; i < exits.length; i += 1) { + if (exits[i].target === this.prevAreas[me.area]) { + this.hooks.push({ + name: "Previous Area", + destination: this.prevAreas[me.area], + hook: new Text("Num 1: " + Pather.getAreaName(this.prevAreas[me.area]), 150, 525 - (this.hooks.length * 10)) + }); + + break; + } + } + + // Check nextAreas first + for (i = 0; i < exits.length; i += 1) { + if (exits[i].target === nextAreas[me.area]) { + this.hooks.push({ + name: "Next Area", + destination: nextAreas[me.area], + hook: new Text("Num 0: " + Pather.getAreaName(nextAreas[me.area]), 150, 525 - (this.hooks.length * 10)) + }); + + nextCheck = true; + + break; + } + } + + // In case the area isn't in nextAreas array, use this.prevAreas array + if (!nextCheck) { + for (i = 0; i < exits.length; i += 1) { + if (exits[i].target === this.prevAreas.indexOf(me.area)) { + this.hooks.push({ + name: "Next Area", + destination: this.prevAreas.indexOf(me.area), + hook: new Text("Num 0: " + Pather.getAreaName(this.prevAreas.indexOf(me.area)), 150, 525 - (this.hooks.length * 10)) + }); + + break; + } + } + } + } + }, + + getHook: function (name) { + var i; + + for (i = 0; i < this.hooks.length; i += 1) { + if (this.hooks[i].name === name) { + return this.hooks[i]; + } + } + + return false; + }, + + flush: function () { + while (this.hooks.length) { + this.hooks.shift().hook.remove(); + } + + removeEventListener("keyup", this.event); + + this.currArea = 0; + } + }, + + update: function () { + while (!me.gameReady) { + delay(100); + } + + this.monsters.check(); + this.text.check(); + this.vector.check(); + this.tele.check(); + }, + + flush: function () { + this.monsters.flush(); + this.text.flush(); + this.vector.flush(); + this.tele.flush(); + + return true; + } +}; + +function main() { + include("json2.js"); + include("common/attack.js"); + include("common/pather.js"); + load("tools/maphelper.js"); + print("ÿc9Map Thread Loaded"); + + this.revealArea = function (area) { + if (!this.revealedAreas) { + this.revealedAreas = []; + } + + if (this.revealedAreas.indexOf(area) === -1) { + delay(500); + revealLevel(true); + this.revealedAreas.push(area); + } + }; + + this.keyEvent = function (key) { + switch (key) { + case 103: // Numpad 7 + if (Hooks.monsters.enabled) { + Hooks.monsters.enabled = false; + Hooks.text.getHook("monsterStatus").hook.text = "Num 7: Enable Monsters"; + } else { + Hooks.monsters.enabled = true; + Hooks.text.getHook("monsterStatus").hook.text = "Num 7: Disable Monsters"; + } + + break; + case 104: // Numpad 8 + if (Hooks.vector.enabled) { + Hooks.vector.enabled = false; + Hooks.text.getHook("vectorStatus").hook.text = "Num 8: Enable Monsters"; + } else { + Hooks.vector.enabled = true; + Hooks.text.getHook("vectorStatus").hook.text = "Num 8: Disable Monsters"; + } + + break; + } + }; + + var i, + hideFlags = [0x09, 0x0C, 0x0D, 0x01, 0x02, 0x0F, 0x18, 0x19, 0x21]; + + addEventListener("keyup", this.keyEvent); + + while (true) { + while (!me.area || !me.gameReady) { + delay(100); + } + + this.revealArea(me.area); + + if (getUIFlag(UIFlags.Automap_is_on)) { + Hooks.update(); + } else { + Hooks.flush(); + } + + delay(20); + + for (i = 0; i < hideFlags.length; i += 1) { + while (getUIFlag(hideFlags[i])) { + Hooks.flush(); + delay(100); + } + } + } +} \ No newline at end of file diff --git a/d2bs/kolbot/tools/Party.js b/d2bs/kolbot/tools/Party.js index 03fe5348c..83c997207 100644 --- a/d2bs/kolbot/tools/Party.js +++ b/d2bs/kolbot/tools/Party.js @@ -10,64 +10,174 @@ function main() { include("common/Config.js"); include("common/Cubing.js"); include("common/Runewords.js"); + include("common/Misc.js"); + include("common/Prototypes.js"); + include("common/Enums.js"); Config.init(); - var myPartyId, player, otherParty, shitList, + var i, myPartyId, player, otherParty, shitList, currScript, scriptList, + classes = ["Amazon", "Sorceress", "Necromancer", "Paladin", "Barbarian", "Druid", "Assassin"], + playerLevels = {}, partyTick = getTickCount(); - print("ÿc2Party thread loaded. Mode: " + (Config.PublicMode > 1 ? "Accept" : "Invite")); + addEventListener("gameevent", + function (mode, param1, param2, name1, name2) { + var player; - if (Config.ShitList) { + switch (mode) { + case 0x02: // "%Name1(%Name2) joined our world. Diablo's minions grow stronger." + if (Config.Greetings.length > 0) { + try { + player = getParty(name1); + } catch (e1) { + + } + + if (player && player.name !== me.name) { + say(Config.Greetings[rand(0, Config.Greetings.length - 1)].replace("$name", player.name).replace("$level", player.level).replace("$class", classes[player.classid])); + } + } + + break; + case 0x06: // "%Name1 was Slain by %Name2" + if (Config.DeathMessages.length > 0) { + try { + player = getParty(name1); + } catch (e2) { + + } + + if (player && player.name !== me.name) { + say(Config.DeathMessages[rand(0, Config.DeathMessages.length - 1)].replace("$name", player.name).replace("$level", player.level).replace("$class", classes[player.classid]).replace("$killer", name2)); + } + } + + break; + } + }); + addEventListener("scriptmsg", + function (msg) { + var obj; + + try { + obj = JSON.parse(msg); + + if (obj && obj.hasOwnProperty("currScript")) { + currScript = obj.currScript; + } + } catch (e3) { + + } + }); + + print("ÿc2Party thread loaded. Mode: " + (Config.PublicMode === 2 ? "Accept" : "Invite")); + + if (Config.ShitList || Config.UnpartyShitlisted) { shitList = ShitList.read(); print(shitList.length + " entries in shit list."); } + if (Config.PartyAfterScript) { + scriptList = []; + + for (i in Scripts) { + if (Scripts.hasOwnProperty(i) && !!Scripts[i]) { + scriptList.push(i); + } + } + } + // Main loop while (true) { - player = getParty(); - - if (player) { - myPartyId = player.partyid; + if (me.gameReady && (!Config.PartyAfterScript || scriptList.indexOf(currScript) > scriptList.indexOf(Config.PartyAfterScript))) { + player = getParty(); + + if (player) { + myPartyId = player.partyid; + + while (player.getNext()) { + switch (Config.PublicMode) { + case 1: // Invite others + case 3: // Invite others but never accept + if (getPlayerFlag(me.gid, player.gid, 8)) { + if (Config.ShitList && shitList.indexOf(player.name) === -1) { + say(player.name + " has been shitlisted."); + shitList.push(player.name); + ShitList.add(player.name); + } + + if (player.partyflag === 4) { + clickParty(player, ClickTypeParty.Join_party); // cancel invitation + delay(100); + } + + break; + } - while (player.getNext()) { - switch (Config.PublicMode) { - case 1: - if (getPlayerFlag(me.gid, player.gid, 8)) { - if (Config.ShitList && shitList.indexOf(player.name) === -1) { - shitList.push(player.name); - ShitList.add(player.name); + if (Config.ShitList && shitList.indexOf(player.name) > -1) { + break; } - if (player.partyflag === 4) { - clickParty(player, 2); // cancel invitation + if (player.partyflag !== 4 && (Config.PublicMode === 1 || player.partyflag !== 2) && player.partyid === 65535) { + clickParty(player, ClickTypeParty.Join_party); delay(100); } break; - } + case 2: // Accept invites + if (Config.Leader && player.name !== Config.Leader) { + break; + } + + if (player.partyid !== 65535 && player.partyid !== myPartyId) { + otherParty = player.partyid; + } + + if (player.partyflag === 2 && (!otherParty || player.partyid === otherParty) && (getTickCount() - partyTick >= 2000 || Config.FastParty)) { + clickParty(player, ClickTypeParty.Join_party); + delay(100); + } - if (Config.ShitList && shitList.indexOf(player.name) > -1) { break; } - if (player.partyflag !== 4 && player.partyid === 65535) { - clickParty(player, 2); - delay(100); - } + 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); + } - break; - case 2: - if (player.partyid !== 65535 && player.partyid !== myPartyId) { - otherParty = player.partyid; - } + 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."); + } - if (player.partyflag === 2 && (!otherParty || player.partyid === otherParty) && (getTickCount() - partyTick >= 2000)) { - clickParty(player, 2); - delay(100); + clickParty(player, ClickTypeParty.Leave_party); + delay(100); + } } + } + } + + if (Config.Congratulations.length > 0) { + player = getParty(); + + if (player) { + do { + if (player.name !== me.name) { + if (!playerLevels[player.name]) { + playerLevels[player.name] = player.level; + } - break; + if (player.level > playerLevels[player.name]) { + say(Config.Congratulations[rand(0, Config.Congratulations.length - 1)].replace("$name", player.name).replace("$level", player.level).replace("$class", classes[player.classid])); + + playerLevels[player.name] = player.level; + } + } + } while (player.getNext()); } } } diff --git a/d2bs/kolbot/tools/RushThread.js b/d2bs/kolbot/tools/RushThread.js index 75278feee..35a1931d3 100644 --- a/d2bs/kolbot/tools/RushThread.js +++ b/d2bs/kolbot/tools/RushThread.js @@ -10,9 +10,13 @@ include("json2.js"); 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"); include("common/Config.js"); +include("common/CollMap.js"); include("common/Loader.js"); include("common/Misc.js"); include("common/Pickit.js"); @@ -22,6 +26,8 @@ include("common/Prototypes.js"); include("common/Runewords.js"); include("common/Storage.js"); include("common/Town.js"); +include("common/Enums.js"); + var gidList = []; @@ -44,9 +50,36 @@ function main() { return false; }; + this.bumperCheck = function () { + var party = getParty(); + + if (party) { + do { + if (party.name !== me.name) { + switch (me.diff) { + case 0: + if (party.level >= 20) { + return true; + } + + break; + case 1: + if (party.level >= 40) { + return true; + } + + break; + } + } + } while (party.getNext()); + } + + return false; + }; + this.playersInAct = function (act) { var area, party, - areas = [0, 1, 40, 75, 103, 109]; + areas = [Areas.None, Areas.Act1.Rogue_Encampment, Areas.Act2.Lut_Gholein, Areas.Act3.Kurast_Docktown, Areas.Act4.The_Pandemonium_Fortress, Areas.Act5.Harrogath]; if (!act) { act = me.act; @@ -67,28 +100,35 @@ function main() { }; this.andariel = function () { + say("starting andariel"); Town.doChores(); - Pather.useWaypoint(35); + Pather.useWaypoint(Areas.Act1.Catacombs_Level_2, true); Precast.doPrecast(true); - if (!Pather.moveToExit([36, 37], true) || !Pather.moveTo(22587, 9577)) { + if (!Pather.moveToExit([Areas.Act1.Catacombs_Level_3, Areas.Act1.Catacombs_Level_4], true) || !Pather.moveTo(22582, 9612)) { throw new Error("andy failed"); } Pather.makePortal(); - Attack.clear(25); + Attack.securePosition(me.x, me.y, 40, 3000, true); say("1"); while (!this.playerIn()) { - Pather.moveTo(22587, 9577); + Pather.moveTo(22582, 9612); + delay(250); + } + + Attack.kill(UnitClassID.andariel); + say("2"); + Pather.moveTo(22582, 9612); + + while (this.playerIn()) { delay(250); } - Attack.kill("andariel"); - Pather.moveTo(22587, 9577); Pather.usePortal(null, me.name); say("a2"); - Pather.useWaypoint(40); + Pather.useWaypoint(Areas.Act2.Lut_Gholein, true); while (!this.playersInAct(2)) { delay(250); @@ -99,24 +139,24 @@ function main() { this.cube = function () { if (me.diff === 0) { - Pather.useWaypoint(57); + say("starting cube"); + Pather.useWaypoint(Areas.Act2.Halls_Of_The_Dead_Level_2, true); Precast.doPrecast(true); - if (!Pather.moveToExit(60, true) || !Pather.moveToPreset(me.area, 2, 354)) { + if (!Pather.moveToExit(Areas.Act2.Halls_Of_The_Dead_Level_3, true) || !Pather.moveToPreset(me.area, UnitType.Object, UnitClassID.trap_melee)) { throw new Error("cube failed"); } Pather.makePortal(); - Attack.clear(25); + Attack.securePosition(me.x, me.y, 30, 3000, true); say("1"); while (!this.playerIn()) { - Attack.clear(20); - delay(250); + delay(100); } while (this.playerIn()) { - delay(250); + delay(100); } Pather.usePortal(null, me.name); @@ -126,36 +166,31 @@ function main() { }; this.amulet = function () { + say("starting amulet"); Town.doChores(); - Pather.useWaypoint(44); + Pather.useWaypoint(Areas.Act2.Lost_City, true); Precast.doPrecast(true); - if (!Pather.moveToExit([45, 58, 61], true) || !Pather.moveTo(15044, 14045)) { + if (!Pather.moveToExit([Areas.Act2.Valley_Of_Snakes, Areas.Act2.Claw_Viper_Temple_Level_1, Areas.Act2.Claw_Viper_Temple_Level_2], true) || !Pather.moveTo(15044, 14045)) { throw new Error("amulet failed"); } Pather.makePortal(); - say("1"); - - var altaMonsta = getUnit(1), - monList = []; - if (altaMonsta) { - do { - if (Attack.checkMonster(altaMonsta) && (!checkCollision(me, altaMonsta, 1) && getDistance(me, altaMonsta) <= 15)) { - monList.push(copyUnit(altaMonsta)); - } - } while (altaMonsta.getNext()); + if (me.diff < 2) { + Attack.securePosition(me.x, me.y, 25, 3000); + } else { + Attack.securePosition(me.x, me.y, 25, 3000, true, true); } - Attack.clearList(monList); + say("1"); while (!this.playerIn()) { - delay(250); + delay(100); } while (this.playerIn()) { - delay(250); + delay(100); } Pather.usePortal(null, me.name); @@ -164,25 +199,26 @@ function main() { }; this.staff = function () { + say("starting staff"); Town.doChores(); - Pather.useWaypoint(43); + Pather.useWaypoint(Areas.Act2.Far_Oasis, true); Precast.doPrecast(true); - if (!Pather.moveToExit([62, 63, 64], true) || !Pather.moveToPreset(me.area, 2, 356)) { + if (!Pather.moveToExit([Areas.Act2.Maggot_Lair_Level_1, Areas.Act2.Maggot_Lair_Level_2, Areas.Act2.Maggot_Lair_Level_3], true) || !Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Staff_Of_Kings_Chest)) { throw new Error("staff failed"); } Pather.makePortal(); - Attack.clear(25); + Attack.securePosition(me.x, me.y, 30, 3000, true); say("1"); while (!this.playerIn()) { - Pather.moveToPreset(me.area, 2, 356); - delay(250); + //Pather.moveToPreset(me.area, 2, 356); + delay(100); } while (this.playerIn()) { - delay(250); + delay(100); } Pather.usePortal(null, me.name); @@ -196,12 +232,13 @@ function main() { // right down 25830 5447 (25866, 5431) // left down 25447 5822 (25431, 5861) + say("starting summoner"); Town.doChores(); - Pather.useWaypoint(74); + Pather.useWaypoint(Areas.Act2.Arcane_Sanctuary, true); Precast.doPrecast(true); var i, journal, - preset = getPresetUnit(me.area, 2, 357), + preset = getPresetUnit(me.area, UnitType.Object, UniqueObjectIds.Horazons_Journal), spot = {}; switch (preset.roomx * 5 + preset.x) { @@ -229,31 +266,34 @@ function main() { } Pather.makePortal(); - Attack.clear(25); + Attack.securePosition(me.x, me.y, 25, 3000); say("1"); while (!this.playerIn()) { Pather.moveToUnit(spot); - Attack.clear(20); + Attack.securePosition(me.x, me.y, 25, 500); delay(250); } - Attack.clear(15, 0, "the summoner"); + Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Horazons_Journal); + Attack.kill(250); + say("2"); while (this.playerIn()) { - delay(250); + delay(100); } - Pather.moveToPreset(me.area, 2, 357); + Pickit.pickItems(); + Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Horazons_Journal); - journal = getUnit(2, 357); + journal = getUnit(UnitType.Object, UniqueObjectIds.Horazons_Journal); for (i = 0; i < 5; i += 1) { journal.interact(); delay(1000); me.cancel(); - if (Pather.getPortal(46)) { + if (Pather.getPortal(Areas.Act2.Canyon_Of_The_Magi)) { break; } } @@ -262,58 +302,71 @@ function main() { throw new Error("summoner failed"); } - Pather.usePortal(46); + Pather.usePortal(Areas.Act2.Canyon_Of_The_Magi); return true; }; this.duriel = function () { + say("starting duriel"); + if (me.inTown) { Town.doChores(); - Pather.useWaypoint(46); + Pather.useWaypoint(Areas.Act2.Canyon_Of_The_Magi, true); } Precast.doPrecast(true); - if (!Pather.moveToExit(getRoom().correcttomb, true) || !Pather.moveToPreset(me.area, 2, 152)) { + if (!Pather.moveToExit(getRoom().correcttomb, true) || !Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Holder_For_Horadric_Staff)) { throw new Error("duriel failed"); } Pather.makePortal(); - Attack.clear(25); + Attack.securePosition(me.x, me.y, 30, 3000, true, me.diff === 2); say("1"); while (!this.playerIn()) { - Pather.moveToPreset(me.area, 2, 152, 0, -5); - delay(250); + //Pather.moveToPreset(me.area, 2, 152, 0, -5); + delay(100); } while (this.playerIn()) { - delay(250); + delay(100); } - while (!getUnit(2, 100)) { - delay(250); + while (!getUnit(UnitType.Object, UniqueObjectIds.Portal_To_Duriel)) { + delay(500); } - Pather.useUnit(2, 100, 73); - Attack.kill("duriel"); - // duriel's cave is... awkward. it allows tele only to specific spots - Pather.moveTo(22629, 15712); - Pather.moveTo(22612, 15709); - Pather.moveTo(22579, 15705); - Pather.moveTo(22577, 15649); - Pather.moveTo(22577, 15614); + Pather.useUnit(UnitType.Object, UniqueObjectIds.Portal_To_Duriel, Areas.Act2.Duriels_Lair); + Attack.kill(UnitClassID.duriel); + Pickit.pickItems(); + + Pather.teleport = false; + + Pather.moveTo(22579, 15706); + + Pather.teleport = true; + + Pather.moveTo(22577, 15649, 10); + Pather.moveTo(22577, 15609, 10); Pather.makePortal(); say("1"); while (!this.playerIn()) { - delay(250); + delay(100); } - Pather.usePortal(null, me.name); + if (!Pather.usePortal(null, me.name)) { + Town.goToTown(); + } + + Pather.useWaypoint(Areas.Act2.Palace_Cellar_Level_1); + Pather.moveToExit([Areas.Act2.Harem_Level_2, Areas.Act2.Harem_Level_1], true); + Pather.moveTo(10022, 5047); say("a3"); - Pather.useWaypoint(75); + Town.goToTown(3); + Town.doChores(); while (!this.playersInAct(3)) { delay(250); @@ -323,64 +376,95 @@ function main() { }; this.travincal = function () { + say("starting travincal"); Town.doChores(); - Pather.useWaypoint(83); + Pather.useWaypoint(Areas.Act3.Travincal, true); Precast.doPrecast(true); var coords = [me.x, me.y]; - Pather.moveTo(coords[0] + 81, coords[1] - 135); + Pather.moveTo(coords[0] + 23, coords[1] - 102); Pather.makePortal(); - Attack.clear(25); + 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)); - Pather.moveTo(coords[0] + 81, coords[1] - 135); + Attack.kill(getLocaleString(2860));*/ + + say("2"); + 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); + Pather.useWaypoint(Areas.Act3.Durance_Of_Hate_Level_2, true); Precast.doPrecast(true); - Pather.moveToExit(102, true); + Pather.moveToExit(Areas.Act3.Durance_Of_Hate_Level_3, true); + Pather.moveTo(17692, 8023); + Pather.makePortal(); + delay(2000); + say("1"); + + while (!this.playerIn()) { + delay(250); + } + Pather.moveTo(17591, 8070); + Attack.kill(UnitClassID.mephisto); + Pickit.pickItems(); + Pather.moveTo(17692, 8023); Pather.makePortal(); + say("2"); - var monsta, - monList = []; + while (this.playerIn()) { + delay(250); + } - monsta = getUnit(1); + Pather.moveTo(17591, 8070); + Attack.securePosition(me.x, me.y, 40, 3000); + + hydra = getUnit(UnitType.NPC, "hydra"); - if (monsta) { + if (hydra) { do { - if (Attack.checkMonster(monsta) && getDistance(me, monsta) <= 25) { - monList.push(copyUnit(monsta)); + while (hydra.mode !== NPCModes.death && hydra.mode !== NPCModes.dead && hydra.hp > 0) { + delay(500); } - } while (monsta.getNext()); + } while (hydra.getNext()); } - Attack.clearList(monList); + Pather.makePortal(); + Pather.moveTo(17581, 8070); say("1"); while (!this.playerIn()) { - Pather.moveTo(17591, 8070); delay(250); } - Attack.kill("mephisto"); say("a4"); - Pather.moveTo(17591, 8070); + //Pather.moveTo(17591, 8070); + + while (!this.playersInAct(4)) { + delay(250); + } + delay(2000); Pather.usePortal(null); @@ -388,8 +472,10 @@ function main() { }; this.diablo = function () { + say("starting diablo"); + this.getLayout = function (seal, value) { - var sealPreset = getPresetUnit(108, 2, seal); + var sealPreset = getPresetUnit(Areas.Act4.Chaos_Sanctuary, States.POISON, seal); if (!seal) { throw new Error("Seal preset not found. Can't continue."); @@ -403,20 +489,27 @@ function main() { }; this.initLayout = function () { - this.vizLayout = this.getLayout(396, 5275); - this.seisLayout = this.getLayout(394, 7773); - this.infLayout = this.getLayout(392, 7893); + this.vizLayout = this.getLayout(UniqueObjectIds.Diablo_Seal5, 5275); + this.seisLayout = this.getLayout(UniqueObjectIds.Diablo_Seal3, 7773); + this.infLayout = this.getLayout(UniqueObjectIds.Diablo_Seal1, 7893); }; this.getBoss = function (name) { var i, boss, - glow = getUnit(2, 131); + glow = getUnit(UnitType.Object, UniqueObjectIds.Vile_Dog_Afterglow); - for (i = 0; i < (name === getLocaleString(2853) ? 12 : 10); i += 1) { - boss = getUnit(1, name); + for (i = 0; i < (name === getLocaleString(2853) ? 14 : 12); i += 1) { + boss = getUnit(UnitType.NPC, name); if (boss) { - return Attack.clear(40, 0, name); + if (name === getLocaleString(2852)) { + this.chaosPreattack(getLocaleString(2852), 8); + } + + Attack.kill(name); + Pickit.pickItems(); + + return true; } delay(250); @@ -425,135 +518,150 @@ function main() { return !!glow; }; - this.openSeal = function (classid) { - var i, seal, warn; + this.chaosPreattack = function (name, amount) { + var i, n, target, positions; - switch (classid) { - case 396: - case 394: - case 392: - warn = true; + switch (me.classid) { + case UnitClassID.skeleton1: break; - default: - warn = false; + case UnitClassID.skeleton2: break; - } + case UnitClassID.skeleton3: + break; + case UnitClassID.skeleton4: + target = getUnit(1, name); - for (i = 0; i < 5; i += 1) { - Pather.moveToPreset(me.area, 2, classid, classid === 394 ? 5 : 2, classid === 394 ? 5 : 0); + if (!target) { + return; + } - seal = getUnit(2, classid); + positions = [[6, 11], [0, 8], [8, -1], [-9, 2], [0, -11], [8, -8]]; - if (!seal) { - return false; - } + 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); - if (seal.mode) { // for pubbies - if (warn) { - say("Leave the seals alone you soggy cunt!"); - } + for (n = 0; n < amount; n += 1) { + Skill.cast(Config.AttackSkill[1], 1); + } - return true; + break; + } } - warn = false; + break; + case UnitClassID.skeleton5: + break; + case UnitClassID.zombie1: + break; + case UnitClassID.zombie2: + break; + } + }; - seal.interact(); - delay(classid === 394 ? 1000 : 500); + this.openSeal = function (id) { + Pather.moveToPreset(Areas.Act4.Chaos_Sanctuary, UnitType.Object, id, 4); - 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); - } + var i, tick, + seal = getUnit(UnitType.Object, id); - delay(500); - } else { - return true; + if (seal) { + for (i = 0; i < 3; i += 1) { + seal.interact(); + + tick = getTickCount(); + + while (getTickCount() - tick < 500) { + if (seal.mode) { + return true; + } + + delay(10); + } } } return false; }; - this.vizierSeal = function () { - if (!this.openSeal(395) || !this.openSeal(396)) { - throw new Error("Failed to open Vizier seals."); - } - - if (this.vizLayout === 1) { - Pather.moveTo(7691, 5292); - } else { - Pather.moveTo(7695, 5316); - } - - if (!this.getBoss(getLocaleString(2851))) { - throw new Error("Failed to kill Vizier"); - } + Town.doChores(); + Pather.useWaypoint(Areas.Act4.River_Of_Flame, true); + Precast.doPrecast(true); + Pather.moveTo(7790, 5544); + this.initLayout(); - return true; - }; + if (!this.openSeal(UniqueObjectIds.Diablo_Seal4) || !this.openSeal(UniqueObjectIds.Diablo_Seal5)) { + throw new Error("Failed to open seals"); + } - this.seisSeal = function () { - if (!this.openSeal(394)) { - throw new Error("Failed to open de Seis seal."); - } + if (this.vizLayout === 1) { + Pather.moveTo(7691, 5292); + } else { + Pather.moveTo(7695, 5316); + } - if (this.seisLayout === 1) { - Pather.moveTo(7771, 5196); - } else { - Pather.moveTo(7798, 5186); - } + if (!this.getBoss(getLocaleString(2851))) { + throw new Error("Failed to kill Vizier"); + } - if (!this.getBoss(getLocaleString(2852))) { - throw new Error("Failed to kill de Seis"); - } + if (!this.openSeal(UniqueObjectIds.Diablo_Seal3)) { + throw new Error("Failed to open seals"); + } - return true; - }; + if (this.seisLayout === 1) { + Pather.moveTo(7771, 5196); + } else { + Pather.moveTo(7798, 5186); + } - this.infectorSeal = function () { - if (!this.openSeal(393) || !this.openSeal(392)) { - throw new Error("Failed to open Infector seals."); - } + if (!this.getBoss(getLocaleString(2852))) { + throw new Error("Failed to kill de Seis"); + } - if (this.infLayout === 1) { - delay(1); - } else { - Pather.moveTo(7928, 5295); // temp - } + if (!this.openSeal(UniqueObjectIds.Diablo_Seal1) || !this.openSeal(UniqueObjectIds.Diablo_Seal2)) { + throw new Error("Failed to open seals"); + } - if (!this.getBoss(getLocaleString(2853))) { - throw new Error("Failed to kill Infector"); - } + if (this.infLayout === 1) { + delay(1); + } else { + Pather.moveTo(7928, 5295); // temp + } - return true; - }; + if (!this.getBoss(getLocaleString(2853))) { + throw new Error("Failed to kill Infector"); + } - Town.doChores(); - Pather.useWaypoint(107); - Precast.doPrecast(true); - Pather.moveTo(7790, 5544); - this.initLayout(); - this.vizierSeal(); - this.seisSeal(); - this.infectorSeal(); Pather.moveTo(7763, 5267); Pather.makePortal(); + Pather.moveTo(7727, 5267); say("1"); while (!this.playerIn()) { delay(250); } - while (!getUnit(1, 243)) { + Pather.moveTo(7763, 5267); + + while (!getUnit(UnitType.NPC, UnitClassID.diablo)) { delay(500); } - Attack.kill("diablo"); + Attack.kill(UnitClassID.diablo); + say("2"); + + if (me.gametype > 0) { + say("a5"); + + while (!this.playersInAct(5)) { + delay(250); + } + } + + Pickit.pickItems(); - if (!Pather.makePortal(null, me.name)) { + if (!Pather.usePortal(null, me.name)) { Town.goToTown(); } @@ -561,54 +669,87 @@ function main() { }; this.ancients = 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 ancients"); + var altar; Town.doChores(); - Pather.useWaypoint(118); + Pather.useWaypoint(Areas.Act5.Ancients_Way, true); Precast.doPrecast(true); - if (!Pather.moveToExit(120, true)) { + if (!Pather.moveToExit(Areas.Act5.Arreat_Summit, true)) { throw new Error("Failed to go to Ancients way."); } - Pather.moveTo(10057, 12645); + Pather.moveTo(10089, 12622); Pather.makePortal(); - say("1"); + say("3"); while (!this.playerIn()) { delay(250); } - altar = getUnit(2, 546); + Pather.moveTo(10048, 12628); + + altar = getUnit(UnitType.Object, UniqueObjectIds.AncientsAltar); if (altar) { - while (altar.mode !== 2) { + while (altar.mode !== ObjectModes.Opened) { Pather.moveToUnit(altar); altar.interact(); - delay(1000); + delay(2000 + me.ping); me.cancel(); } } - while (!getUnit(1, 542)) { + while (!getUnit(UnitType.NPC, UnitClassID.ancientbarb3)) { delay(250); } Attack.clear(50); - Pather.moveTo(10057, 12645); - Town.goToTown(); + Pather.moveTo(10089, 12622); + me.cancel(); + Pather.makePortal(); + + while (this.playerIn()) { + delay(100); + } + + if (!Pather.usePortal(null, me.name)) { + Town.goToTown(); + } + + return true; }; this.baal = function () { + say("starting baal"); + var tick, portal; this.preattack = function () { var check; switch (me.classid) { - case 1: - if ([56, 59, 64].indexOf(Config.AttackSkill[1]) > -1) { - if (me.getState(121)) { + case ClassID.Sorceress: + if ([Skills.Sorceress.Meteor, Skills.Sorceress.Blizzard, Skills.Sorceress.Frozen_Orb].indexOf(Config.AttackSkill[1]) > -1) { + if (me.getState(States.SKILLDELAY)) { delay(500); } else { Skill.cast(Config.AttackSkill[1], 0, 15093, 5024); @@ -616,8 +757,8 @@ function main() { } return true; - case 3: // Paladin - if (Config.AttackSkill[3] !== 112) { + case ClassID.Paladin: // Paladin + if (Config.AttackSkill[3] !== Skills.Paladin.Blessed_Hammer) { return false; } @@ -632,15 +773,15 @@ function main() { Skill.cast(Config.AttackSkill[3], 1); return true; - case 5: // Druid - if (Config.AttackSkill[3] === 245) { + case ClassID.Druid: // Druid + if (Config.AttackSkill[3] === Skills.Druid.Tornado) { Skill.cast(Config.AttackSkill[3], 0, 15093, 5029); return true; } break; - case 6: + case ClassID.Assassin: if (Config.UseTraps) { check = ClassAttack.checkTraps({x: 15093, y: 5029}); @@ -658,23 +799,23 @@ function main() { }; this.checkThrone = function () { - var monster = getUnit(1); + var monster = getUnit(UnitType.NPC); if (monster) { do { if (Attack.checkMonster(monster) && monster.y < 5080) { switch (monster.classid) { - case 23: - case 62: + case UnitClassID.fallen5: + case UnitClassID.fallenshaman5: return 1; - case 105: - case 381: + case UnitClassID.unraveler5: + case UnitClassID.skmage_cold3: return 2; - case 557: + case UnitClassID.baalhighpriest: return 3; - case 558: + case UnitClassID.venomlord: return 4; - case 571: + case UnitClassID.baalminion1: return 5; default: Attack.getIntoPosition(monster, 10, 0x4); @@ -695,7 +836,7 @@ function main() { pos = [15097, 5054, 15085, 5053, 15085, 5040, 15098, 5040, 15099, 5022, 15086, 5024]; if (Config.AvoidDolls) { - monster = getUnit(1, 691); + monster = getUnit(UnitType.NPC, UnitClassID.bonefetish7); if (monster) { do { @@ -717,14 +858,14 @@ function main() { }; this.checkHydra = function () { - var monster = getUnit(1, "hydra"); + var monster = getUnit(UnitType.NPC, "hydra"); if (monster) { do { - if (monster.mode !== 12 && monster.getStat(172) !== 2) { + if (monster.mode !== NPCModes.dead && monster.getStat(Stats.alignment) !== 2) { Pather.moveTo(15118, 5002); - while (monster.mode !== 12) { + while (monster.mode !== NPCModes.dead) { delay(500); if (!copyUnit(monster).x) { @@ -740,12 +881,14 @@ function main() { return true; }; - Town.doChores(); - Pather.useWaypoint(129); - Precast.doPrecast(true); + if (me.inTown) { + Town.doChores(); + Pather.useWaypoint(Areas.Act5.The_Worldstone_Keep_Level_2, true); + Precast.doPrecast(true); - if (!Pather.moveToExit([130, 131], true)) { - throw new Error("Failed to move to Throne of Destruction."); + if (!Pather.moveToExit([Areas.Act5.The_Worldstone_Keep_Level_3, Areas.Act5.Throne_Of_Destruction], true)) { + throw new Error("Failed to move to Throne of Destruction."); + } } Pather.moveTo(15113, 5040); @@ -753,15 +896,15 @@ function main() { this.clearThrone(); tick = getTickCount(); - Pather.moveTo(15093, me.classid === 3 ? 5029 : 5039); + Pather.moveTo(15093, me.classid === ClassID.Paladin ? 5029 : 5039); MainLoop: while (true) { - if (getDistance(me, 15093, me.classid === 3 ? 5029 : 5039) > 3) { - Pather.moveTo(15093, me.classid === 3 ? 5029 : 5039); + if (getDistance(me, 15093, me.classid === ClassID.Paladin ? 5029 : 5039) > 3) { + Pather.moveTo(15093, me.classid === ClassID.Paladin ? 5029 : 5039); } - if (!getUnit(1, 543)) { + if (!getUnit(UnitType.NPC, UnitClassID.baalthrone)) { break MainLoop; } @@ -799,8 +942,8 @@ MainLoop: break MainLoop; default: if (getTickCount() - tick < 7e3) { - if (me.getState(2)) { - Skill.setSkill(109, 0); + if (me.getState(States.POISON)) { + Skill.setSkill(Skills.Paladin.Cleansing, 0); } break; @@ -817,16 +960,17 @@ MainLoop: delay(10); } + this.clearThrone(); Pather.moveTo(15092, 5011); Precast.doPrecast(true); - while (getUnit(1, 543)) { + while (getUnit(UnitType.NPC, UnitClassID.baalthrone)) { delay(500); } delay(1000); - portal = getUnit(2, 563); + portal = getUnit(UnitType.Object, UniqueObjectIds.Worldstone_Chamber); if (portal) { Pather.usePortal(null, null, portal); @@ -834,24 +978,363 @@ MainLoop: throw new Error("Couldn't find portal."); } + Pather.moveTo(15213, 5908); Pather.makePortal(); - say("1"); + Pather.moveTo(15170, 5950); + delay(1000); + say("3"); while (!this.playerIn()) { delay(250); } Pather.moveTo(15134, 5923); - Attack.kill(544); // Baal + Attack.kill(UnitClassID.baalcrab); // Baal Pickit.pickItems(); return true; }; - var command, + this.clearArea = function (area) { + Pather.journeyTo(area); + Attack.clearLevel(0); + say("Done clearing area: " + area); + }; + + // Quests + 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, 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 + }); + } + } catch (e) { + + } + } + + if (coords.length > 0) { + coords.sort(Sort.units); + + return Pather.moveToUnit(coords[0]); + } + + return false; + }; + + Pather.useWaypoint(Areas.Act2.A2_Sewers_Level_2, true); + Precast.doPrecast(false); + Pather.moveToExit(Areas.Act2.A2_Sewers_Level_3, true); + + radaPreset = getPresetUnit(Areas.Act2.A2_Sewers_Level_3, UnitType.Object, UniqueObjectIds.Horadric_Scroll_Chest); + radaCoords = { + area: Areas.Act2.A2_Sewers_Level_3, + x: radaPreset.roomx * 5 + radaPreset.x, + y: radaPreset.roomy * 5 + radaPreset.y + }; + + moveIntoPos(radaCoords, 50); + + for (i = 0; i < 3; i += 1) { + rada = getUnit(UnitType.NPC, UnitClassID.radament); + + 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(UnitClassID.radament); // 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(UnitType.Item, ItemClassIds.Book_Of_Skill)) { + 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(Areas.Act3.Kurast_Bazaar, true)) { + throw new Error("Lam Essen quest failed"); + } + + Precast.doPrecast(false); + + if (!Pather.moveToExit(Areas.Act3.Ruined_Temple, true) || !Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Lam_Esens_Tome)) { + 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 + }); + } + } catch (e) { + + } + } + + if (coords.length > 0) { + coords.sort(Sort.units); + + return Pather.moveToUnit(coords[0]); + } + + return false; + }; + + Pather.useWaypoint(Areas.Act4.City_Of_The_Damned, true); + Precast.doPrecast(false); + Pather.moveToExit(Areas.Act4.Plains_Of_Despair, true); + + izualPreset = getPresetUnit(Areas.Act4.Plains_Of_Despair, UnitType.NPC, UnitClassID.izual); + izualCoords = { + area: Areas.Act4.Plains_Of_Despair, + x: izualPreset.roomx * 5 + izualPreset.x, + y: izualPreset.roomy * 5 + izualPreset.y + }; + + moveIntoPos(izualCoords, 50); + + for (i = 0; i < 3; i += 1) { + izual = getUnit(UnitType.NPC, UnitClassID.izual); + + if (izual) { + break; + } + + delay(500); + } + + if (izual) { + moveIntoPos(izual, 60); + } else { + print("izual unit not found"); + } + + returnSpot = { + x: me.x, + y: me.y + }; + + Attack.securePosition(me.x, me.y, 30, 3000); + Pather.makePortal(); + say("1"); + + while (!this.playerIn()) { + delay(200); + } + + Attack.kill(UnitClassID.izual); // Izual + Pickit.pickItems(); + say("2"); + Pather.moveToUnit(returnSpot); + + while (this.playerIn()) { + delay(200); + } + + Pather.usePortal(null, null); + + return true; + }; + + this.shenk = function () { + if (!Config.Rusher.Shenk) { + return false; + } + + say("starting shenk"); + + Pather.useWaypoint(Areas.Act5.Frigid_Highlands, true); + Precast.doPrecast(false); + Pather.moveTo(3846, 5120); + Attack.securePosition(me.x, me.y, 30, 3000); + Pather.makePortal(); + say("1"); + + 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(Areas.Act5.Crystalized_Passage, true)) { + throw new Error("Anya quest failed"); + } + + Precast.doPrecast(false); + + if (!Pather.moveToExit(Areas.Act5.Frozen_River, true) || !Pather.moveToPreset(me.area, UnitType.Object, UniqueObjectIds.Drehya_Outside_Town)) { + throw new Error("Anya quest failed"); + } + + Attack.securePosition(me.x, me.y, 30, 2000); + + anya = getUnit(UnitType.Object, UniqueObjectIds.Frozen_Anya); + + 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()) { + delay(200); + } + + while (getUnit(UnitType.Object, UniqueObjectIds.Frozen_Anya)) { + delay(1000); + } + + say("2"); // Mainly for non-questers to know when to get the scroll of resistance + + while (this.playerIn()) { + delay(200); + } + + Pather.usePortal(null, null); + + return true; + }; + + print("Loading RushThread"); + + var i, command, current = 0, - thisThread = getScript("tools/rushthread.js"), - 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; @@ -861,49 +1344,95 @@ MainLoop: // Start Config.init(false); - Pickit.init(); + Pickit.init(false); Attack.init(); Storage.Init(); + CraftingSystem.buildLists(); + Runewords.init(); + Cubing.init(); while (true) { 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"); + + return true; } try { this[sequence[current]](); } catch (sequenceError) { say(sequenceError.message); + say("2"); Town.goToTown(); } current += 1; - thisThread.send("go"); + command = "go"; break; default: - if (sequence.indexOf(command) > -1) { - current = sequence.indexOf(command); + if (command.split(" ")[0] !== undefined && command.split(" ")[0] === "skiptoact") { + if (!isNaN(parseInt(command.split(" ")[1], 10))) { + switch (parseInt(command.split(" ")[1], 10)) { + case 2: + current = sequence.indexOf("andariel") + 1; + + break; + case 3: + current = sequence.indexOf("duriel") + 1; + + break; + case 4: + current = sequence.indexOf("mephisto") + 1; + + break; + case 5: + current = sequence.indexOf("diablo") + 1; + + break; + } + } + } else if (command.split(" ")[0] !== undefined && command.split(" ")[0] === "clear") { + this.clearArea(Number(command.split(" ")[1])); + Town.goToTown(); + + command = "go"; + } else { + for (i = 0; i < sequence.length; i += 1) { + if (command && sequence[i].match(command, "gi")) { + current = i; + + break; + } + } Town.goToTown(); - thisThread.send("go"); + + command = "go"; + + break; } break; } - command = false; + //command = false; } delay(100); } return true; -} \ No newline at end of file +} diff --git a/d2bs/kolbot/tools/ToolsThread.js b/d2bs/kolbot/tools/ToolsThread.js index d6b6609f9..0460dba47 100644 --- a/d2bs/kolbot/tools/ToolsThread.js +++ b/d2bs/kolbot/tools/ToolsThread.js @@ -4,20 +4,49 @@ * @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"); +include("common/Enums.js"); + + function main() { - var i, mercHP, ironGolem, + var i, mercHP, ironGolem, tick, merc, + debugInfo = {area: 0, currScript: "no entry"}, + pingTimer = [], quitFlag = false, + cloneWalked = false, + canQuit = true, timerLastDrink = []; - include("OOG.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"); print("ÿc3Start ToolsThread script"); - Config.init(); + D2Bot.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; @@ -28,22 +57,83 @@ function main() { me.chickenmp = -1; // General functions - this.getPotion = function (pottype) { - var i, length, + this.checkPing = function (print) { + // Quit after at least 5 seconds in game + if (getTickCount() - me.gamestarttime < 5000) { + return false; + } + + var i; + + for (i = 0; i < Config.PingQuit.length; i += 1) { + if (Config.PingQuit[i].Ping > 0) { + if (me.ping >= Config.PingQuit[i].Ping) { + me.overhead("High Ping"); + + if (pingTimer[i] === undefined || pingTimer[i] === 0) { + pingTimer[i] = getTickCount(); + } + + if (getTickCount() - pingTimer[i] >= Config.PingQuit[i].Duration * 1000) { + if (print) { + D2Bot.printToConsole("High ping (" + me.ping + "/" + Config.PingQuit[i].Ping + ") - leaving game.", 9); + } + + scriptBroadcast("pingquit"); + + return true; + } + } else { + pingTimer[i] = 0; + } + } + } + + 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; } - for (i = 0, length = items.length; i < length; i = i + 1) { - if (pottype === 78 && items[i].mode === 0 && items[i].location === 3 && items[i].itemType === 78) { - print("ÿc2Drinking rejuventation potion from inventory."); + // 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 === ItemModes.Item_In_Inventory_Stash_Cube_Or_Store && items[i].location === ItemLocation.Inventory && items[i].itemType === pottype) { + print("ÿc2Drinking potion from inventory."); return copyUnit(items[i]); } - if (items[i].mode === 2 && items[i].itemType === pottype) { + if (items[i].mode === ItemModes.Item_in_belt && items[i].itemType === pottype) { return copyUnit(items[i]); } } @@ -52,17 +142,48 @@ function main() { }; this.togglePause = function () { - var script = getScript("default.dbj"); + var i, script, + scripts = ["default.dbj", "tools/townchicken.js", "tools/antihostile.js", "tools/party.js", "tools/rushthread.js"]; - if (script) { - if (script.running) { - print("ÿc1Pausing."); - script.pause(); - } else { - print("ÿc2Resuming."); - script.resume(); + for (i = 0; i < scripts.length; i += 1) { + script = getScript(scripts[i]); + + if (script) { + if (script.running) { + if (i === 0) { // default.dbj + print("ÿc1Pausing."); + } + + // don't pause townchicken during clone walk + if (scripts[i] !== "tools/townchicken.js" || !cloneWalked) { + script.pause(); + } + } else { + if (i === 0) { // default.dbj + print("ÿc2Resuming."); + } + + script.resume(); + } } } + + return true; + }; + + this.stopDefault = function () { + var script = getScript("default.dbj"); + + if (script && script.running) { + script.stop(); + } + + return true; + }; + + this.exit = function () { + this.stopDefault(); + quit(); }; this.drinkPotion = function (type) { @@ -72,14 +193,14 @@ function main() { switch (type) { case 0: case 1: - if ((timerLastDrink[type] && (tNow - timerLastDrink[type] < 1000)) || me.getState(type === 0 ? 100 : 106)) { + if ((timerLastDrink[type] && (tNow - timerLastDrink[type] < 1000)) || me.getState(type === 0 ? States.HEALTHPOT : States.MANAPOT)) { return false; } 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; } @@ -92,34 +213,41 @@ function main() { break; } - if (me.mode === 0 || me.mode === 17 || me.mode === 18) { // mode 18 - can't drink while leaping/whirling etc. + if (me.mode === PlayerModes.Death || me.mode === PlayerModes.Dead || me.mode === PlayerModes.Sequence) { // mode 18 - can't drink while leaping/whirling etc. return false; } switch (type) { case 0: case 3: - pottype = 76; + pottype = NTItemTypes.healingpotion; + break; case 1: - pottype = 77; + pottype = NTItemTypes.manapotion; + break; default: - pottype = 78; + pottype = NTItemTypes.rejuvpotion; + break; } - potion = this.getPotion(pottype); + potion = this.getPotion(pottype, type); if (potion) { - if (me.mode === 0 || me.mode === 17) { + if (me.mode === PlayerModes.Death || me.mode === PlayerModes.Dead) { return false; } if (type < 3) { potion.interact(); } else { - clickItem(2, potion); + try { + clickItem(ClickType.Shift_Left_Click, potion); + } catch (e) { + print("Couldn't give the potion to merc."); + } } timerLastDrink[type] = getTickCount(); @@ -132,12 +260,12 @@ function main() { this.getNearestMonster = function () { var gid, distance, - monster = getUnit(1), + monster = getUnit(UnitType.NPC), range = 30; if (monster) { do { - if (monster.hp > 0 && !monster.getParent()) { + if (monster.hp > 0 && Attack.checkMonster(monster) && !monster.getParent()) { distance = getDistance(me, monster); if (distance < range) { @@ -148,57 +276,180 @@ function main() { } while (monster.getNext()); } - monster = getUnit(1, -1, -1, gid); + if (gid) { + monster = getUnit(1, -1, -1, gid); + } else { + monster = false; + } + + if (monster) { + return " to " + monster.name; + } + + return ""; + }; + + this.checkVipers = function () { + var owner, + monster = getUnit(UnitType.NPC, UnitClassID.clawviper9); if (monster) { - return ". Nearest monster: " + monster.name; + do { + if (monster.getState(States.REVIVE)) { + owner = monster.getParent(); + + if (owner && owner.name !== me.name) { + return true; + } + } + } while (monster.getNext()); } - return "."; + return false; }; this.getIronGolem = function () { - var golem = getUnit(1, "iron golem"); + var owner, + golem = getUnit(UnitType.NPC, UnitClassID.irongolem); - if (!golem) { - return false; + if (golem) { + do { + owner = golem.getParent(); + + if (owner && owner.name === me.name) { + return copyUnit(golem); + } + } while (golem.getNext()); } - do { - if (golem.getParent().name === me.name) { - return golem; + return false; + }; + + 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; } - } while (golem.getNext()); + } - return false; + return id || ""; }; // Event functions - this.revealArea = function (area) { - var room = getRoom(area); + this.keyEvent = function (key) { + switch (key) { + case 19: // Pause/Break key + this.togglePause(); + + break; + case 123: // F12 key + me.overhead("Revealing " + Pather.getAreaName(me.area)); + revealLevel(true); + + break; + case 107: // Numpad + + showConsole(); + print("ÿc4MF: ÿc0" + me.getStat(Stats.item_magicbonus) + " ÿc4GF: ÿc0" + me.getStat(Stats.item_goldbonus) + " ÿc1FR: ÿc0" + me.getStat(Stats.fireresist) + + " ÿc3CR: ÿc0" + me.getStat(Stats.coldresist) + " ÿc9LR: ÿc0" + me.getStat(Stats.lightresist) + " ÿc2PR: ÿc0" + me.getStat(Stats.poisonresist)); - do { - if (room instanceof Room && room.area === area) { - room.reveal(true); + break; + case 101: // numpad 5 + if (AutoMule.getInfo() && AutoMule.getInfo().hasOwnProperty("muleInfo")) { + 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."); } - } while (room.getNext()); + + break; + case 102: // Numpad 6 + MuleLogger.logChar(); + + break; + case 109: // Numpad - + Misc.spy(me.name); + + break; + case 110: // decimal point + say("/fps"); + + break; + case 105: // numpad 9 - get nearest preset unit id + print(this.getNearestPreset()); + + break; + } }; - this.quitWithLeader = function (mode, param1, param2, name1, name2) { - if (mode === 0 || mode === 1 || mode === 3) { - if (Config.QuitList.indexOf(name1) > -1) { + 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 ((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; } - } - }; - addEventListener("gameevent", this.quitWithLeader); - addEventListener("scriptmsg", - function (msg) { - switch (msg) { - case "dclone": + if (Config.AntiHostile) { + scriptBroadcast("remove " + name1); + } + + break; + case 0x06: // "%Name1 was Slain by %Name2" + if (Config.AntiHostile && param2 === 0x00 && name2 === me.name) { + scriptBroadcast("mugshot " + name1); + } + + break; + case 0x07: + if (Config.AntiHostile && param2 === 0x03) { // "%Player has declared hostility towards you." + scriptBroadcast("findHostiles"); + } + + break; + case 0x11: // "%Param1 Stones of Jordan Sold to Merchants" + if (Config.DCloneQuit === 2) { + D2Bot.printToConsole("SoJ sold in game. Leaving."); + + quitFlag = true; + + break; + } + + if (Config.SoJWaitTime && me.gametype === GameType.Expansion) { // only do this in expansion + D2Bot.printToConsole(param1 + " Stones of Jordan Sold to Merchants on IP " + me.gameserverip.split(".")[3], 7); + Messaging.sendToScript("default.dbj", "soj"); + } + + break; + case 0x12: // "Diablo Walks the Earth" + if (Config.DCloneQuit > 0) { + D2Bot.printToConsole("Diablo walked in game. Leaving."); + + quitFlag = true; + + break; + } + + if (Config.StopOnDClone && me.gametype === GameType.Expansion) { // only do this in expansion + D2Bot.printToConsole("Diablo Walks the Earth", 7); + + cloneWalked = true; + this.togglePause(); Town.goToTown(); showConsole(); @@ -206,110 +457,187 @@ function main() { me.maxgametime = 0; - break; + if (Config.KillDclone) { + load("tools/clonekilla.js"); + } } + + break; } - ); + }; - addEventListener("keyup", - function (key) { - switch (key) { - case 19: // Pause/Break key - this.togglePause(); + this.scriptEvent = function (msg) { + var obj; - break; - case 123: // F12 key - me.overhead("Revealing " + getArea().name); - this.revealArea(me.area); + switch (msg) { + case "toggleQuitlist": + canQuit = !canQuit; - break; + break; + case "quit": + quitFlag = true; + + break; + default: + try { + obj = JSON.parse(msg); + } catch (e) { + return; } - } - ); - while (me.ingame) { - if (!me.gameReady) { - delay(200); + if (obj) { + if (obj.hasOwnProperty("currScript")) { + debugInfo.currScript = obj.currScript; + } - continue; - } + if (obj.hasOwnProperty("lastAction")) { + debugInfo.lastAction = obj.lastAction; + } - if (!me.inTown) { - if (Config.UseHP > 0 && me.hp < Math.floor(me.hpmax * Config.UseHP / 100)) { - this.drinkPotion(0); + //D2Bot.store(JSON.stringify(debugInfo)); + DataFile.updateStats("debugInfo", JSON.stringify(debugInfo)); } - if (Config.UseRejuvHP > 0 && me.hp < Math.floor(me.hpmax * Config.UseRejuvHP / 100)) { - this.drinkPotion(2); - } + break; + } + }; - if (Config.LifeChicken > 0 && me.hp <= Math.floor(me.hpmax * Config.LifeChicken / 100)) { - D2Bot.updateChickens(); - D2Bot.printToConsole("Life Chicken: " + me.hp + "/" + me.hpmax + " in " + getArea().name + this.getNearestMonster() + ";1"); + // Cache variables to prevent a bug where d2bs loses the reference to Config object + Config = Misc.copy(Config); + tick = getTickCount(); - me.chickenhp = me.hpmax; // Just to trigger the core chicken + addEventListener("keyup", this.keyEvent); + addEventListener("gameevent", this.gameEvent); + addEventListener("scriptmsg", this.scriptEvent); + //addEventListener("gamepacket", Events.gamePacket); - break; - } + // Load Fastmod + Packet.changeStat(Stats.item_fastercastrate, Config.FCR); + Packet.changeStat(Stats.item_fastergethitrate, Config.FHR); + Packet.changeStat(Stats.item_fasterblockrate, Config.FBR); + Packet.changeStat(Stats.item_fasterattackrate, Config.IAS); - if (Config.UseMP > 0 && me.mp < Math.floor(me.mpmax * Config.UseMP / 100)) { - this.drinkPotion(1); - } + if (Config.QuitListMode > 0) { + this.initQuitList(); + } - if (Config.UseRejuvMP > 0 && me.mp < Math.floor(me.mpmax * Config.UseRejuvMP / 100)) { - this.drinkPotion(2); - } + // Start + while (true) { + try { + if (me.gameReady && !me.inTown) { + if (Config.UseHP > 0 && me.hp < Math.floor(me.hpmax * Config.UseHP / 100)) { + this.drinkPotion(0); + } - if (Config.ManaChicken > 0 && me.mp <= Math.floor(me.mpmax * Config.ManaChicken / 100)) { - D2Bot.updateChickens(); - D2Bot.printToConsole("Mana Chicken: " + me.mp + "/" + me.mpmax + " in " + getArea().name + ";1"); + if (Config.UseRejuvHP > 0 && me.hp < Math.floor(me.hpmax * Config.UseRejuvHP / 100)) { + this.drinkPotion(2); + } - me.chickenmp = me.mpmax; // Just to trigger the core chicken + if (Config.LifeChicken > 0 && me.hp <= Math.floor(me.hpmax * Config.LifeChicken / 100)) { + D2Bot.printToConsole("Life Chicken (" + me.hp + "/" + me.hpmax + ")" + this.getNearestMonster() + " in " + Pather.getAreaName(me.area) + ". Ping: " + me.ping, 9); + D2Bot.updateChickens(); + this.exit(); - break; - } + break; + } + + if (Config.UseMP > 0 && me.mp < Math.floor(me.mpmax * Config.UseMP / 100)) { + this.drinkPotion(1); + } - if (Config.IronGolemChicken > 0 && me.classid === 2) { - if (!ironGolem || !copyUnit(ironGolem).x) { - ironGolem = this.getIronGolem(); + if (Config.UseRejuvMP > 0 && me.mp < Math.floor(me.mpmax * Config.UseRejuvMP / 100)) { + this.drinkPotion(2); } - if (ironGolem) { - if (ironGolem.hp <= Math.floor(128 * Config.IronGolemChicken / 100)) { // ironGolem.hpmax is bugged with BO - D2Bot.updateChickens(); - D2Bot.printToConsole("Irom Golem Chicken in " + getArea().name + ";1"); - quit(); + if (Config.ManaChicken > 0 && me.mp <= Math.floor(me.mpmax * Config.ManaChicken / 100)) { + D2Bot.printToConsole("Mana Chicken: (" + me.mp + "/" + me.mpmax + ") in " + Pather.getAreaName(me.area), 9); + D2Bot.updateChickens(); + this.exit(); - break; + break; + } + + if (Config.IronGolemChicken > 0 && me.classid === ClassID.Necromancer) { + if (!ironGolem || copyUnit(ironGolem).x === undefined) { + ironGolem = this.getIronGolem(); + } + + if (ironGolem) { + if (ironGolem.hp <= Math.floor(128 * Config.IronGolemChicken / 100)) { // ironGolem.hpmax is bugged with BO + D2Bot.printToConsole("Irom Golem Chicken in " + Pather.getAreaName(me.area), 9); + D2Bot.updateChickens(); + this.exit(); + + break; + } } } - } - if (Config.UseMerc) { - mercHP = getMercHP(); + if (Config.UseMerc) { + mercHP = getMercHP(); + merc = me.getMerc(); - if (mercHP > 0) { - if (mercHP < Config.MercChicken) { - quit(); + if (mercHP > 0 && merc && merc.mode !== NPCModes.dead) { + if (mercHP < Config.MercChicken) { + D2Bot.printToConsole("Merc Chicken in " + Pather.getAreaName(me.area), 9); + D2Bot.updateChickens(); + this.exit(); - break; + break; + } + + if (mercHP < Config.UseMercHP) { + this.drinkPotion(3); + } + + if (mercHP < Config.UseMercRejuv) { + this.drinkPotion(4); + } } + } - if (mercHP < Config.UseMercRejuv) { - this.drinkPotion(4); - } else if (mercHP < Config.UseMercHP) { - this.drinkPotion(3); + if (Config.ViperCheck && getTickCount() - tick >= 250) { + if (this.checkVipers()) { + D2Bot.printToConsole("Revived Tomb Vipers found. Leaving game.", 9); + + quitFlag = true; } + + tick = getTickCount(); + } + + if (this.checkPing(true)) { + quitFlag = true; } } + } catch (e) { + Misc.errorReport(e, "ToolsThread"); + + quitFlag = true; } - if (quitFlag) { - quit(); + if (quitFlag && canQuit) { + print("ÿc8Run duration ÿc2" + ((getTickCount() - me.gamestarttime) / 1000)); + + if (Config.LogExperience) { + Experience.log(); + } + + this.checkPing(false); // In case of quitlist triggering first + this.exit(); break; } - delay(10); + 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 new file mode 100644 index 000000000..154155b9b --- /dev/null +++ b/d2bs/kolbot/tools/TownChicken.js @@ -0,0 +1,110 @@ +/** +* @filename TownChicken.js +* @author kolton +* @desc handle town chicken +*/ + +js_strict(true); + +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"); +include("common/CollMap.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"); +include("common/Enums.js"); + +function main() { + var townCheck = false; + + this.togglePause = function () { + var i, script, + 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 (i === 0) { // default.dbj + print("ÿc1Pausing."); + } + + script.pause(); + } else { + if (i === 0) { // default.dbj + if (!getScript("tools/clonekilla.js")) { // resume only if clonekilla isn't running + print("ÿc2Resuming."); + script.resume(); + } + } else { + script.resume(); + } + } + } + } + + return true; + }; + + addEventListener("scriptmsg", + function (msg) { + if (msg === "townCheck") { + if (me.area === Areas.UberLevels.Tristram) { + print("Can't tp from uber trist."); + } else { + townCheck = true; + } + } + }); + + // Init config and attacks + D2Bot.init(); + Config.init(); + 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.mp < Math.floor(me.mpmax * Config.TownMP / 100)))) { + this.togglePause(); + + while (!me.gameReady) { + delay(100); + } + + try { + me.overhead("Going to town"); + Town.visitTown(); + } catch (e) { + Misc.errorReport(e, "TownChicken.js"); + scriptBroadcast("quit"); + + return; + } finally { + this.togglePause(); + + townCheck = false; + } + } + + 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 diff --git a/data/cdkeys.json b/data/cdkeys.json new file mode 100644 index 000000000..e69de29bb diff --git a/data/patch.json b/data/patch.json new file mode 100644 index 000000000..ed46927c0 --- /dev/null +++ b/data/patch.json @@ -0,0 +1,10 @@ +// +// Format: name, game version, module #, offset, byte array as character string +// Module list: D2CLIENT=0, D2COMMON=1, D2GFX=2, D2LANG=3, D2WIN=4, D2NET=5, D2GAME=6, +// D2LAUNCH=7, FOG=8, BNCLIENT=9, STORM=10, D2CMP=11, D2MULTI=12, D2MCPCLIENT=13 +// For 1.14d: GAME=14 +// +{"Name":"hidewin0","Version":"1.13d","Module":2,"Offset":47483,"Data":"ahA="} +{"Name":"hidewin1","Version":"1.13d","Module":2,"Offset":47362,"Data":"agY="} +{"Name":"hidewin0","Version":"1.14d","Module":14,"Offset":1005781,"Data":"ahA="} +{"Name":"hidewin1","Version":"1.14d","Module":14,"Offset":1005658,"Data":"agY="} \ No newline at end of file diff --git a/data/profile.json b/data/profile.json new file mode 100644 index 000000000..e69de29bb diff --git a/data/schedules.json b/data/schedules.json new file mode 100644 index 000000000..e69de29bb diff --git a/images/deleteme b/images/deleteme new file mode 100644 index 000000000..e69de29bb diff --git a/logs/Console.rtf b/logs/Console.rtf new file mode 100644 index 000000000..e69de29bb diff --git a/logs/exceptions.log b/logs/exceptions.log new file mode 100644 index 000000000..e69de29bb diff --git a/logs/keyinfo.log b/logs/keyinfo.log new file mode 100644 index 000000000..e69de29bb