Compare commits

..
7 Commits
12 changed files with 52 additions and 24 deletions
+13 -14
View File
@@ -1,8 +1,10 @@
# <img src="assets/docs/header_green.png" width="370">
Simple Pixelbot for Diablo 2 Resurrected written in python and opencv. Obviously only use it in offline mode as it is against the TOS of Blizzard to use it in online mode! [**Download here**](https://github.com/aeon0/botty/releases)
Simple Pixelbot for Diablo 2 Resurrected written in python and opencv. Obviously only use it in offline mode as it is against the TOS of Blizzard to use it online!
[**Download here**](https://github.com/aeon0/botty/releases). Got to have a [**Discord**](https://discord.gg/CnkfsjqN) nowadays I guess :man_shrugging:
Join the [**Discord Channel**](https://discord.gg/CnkfsjqN) for help and discussions.
And please. I urge you to actually read that README! It will make your life a lot easier.
[![Watch the video](assets/docs/video_thumbnail.png)](https://vimeo.com/641410429)
@@ -17,33 +19,28 @@ Join the [**Discord Channel**](https://discord.gg/CnkfsjqN) for help and discuss
- Take potions (health and mana) and chicken if in trouble during fights
- Check for death. In this case start another game and pick up corpse.
- Supported builds: Sorceress (Blizz, Light, Meteor), Hammerdin
- Debug color checker to easily verify your settings
- Auto Settings and Debug Color Mode to easily verify your settings
- Runs in Hyper-V
- Highly configurable, consult the param.ini section for more details
## Getting started
### 1) Graphics and Gameplay Settings
All settings will automatically be set when you execute `run.exe` and press the hotkey for "Adjust D2R settings" (default f9). Note that D2R should not run during this process, or if it does you will have to restart afterwards. The important ones are listed here:
- Resolution: 1920x1080 (Fullscreen)
- Gamma: 155
- Item Label Display: Hold
- Large Font Mode: on
**Note**: There have been issues reported with image sharpening being truned on via the graphic card settings itself outside of D2R. Try turning it off when running the bot.
All settings will automatically be set when you execute `run.exe` and press the hotkey for "Adjust D2R settings" (default f9). Note that D2R should not run during this process, or if it does you will have to restart afterwards. It is not a 100% thing, in rare cases you might still have to fiddle around with your brightness. I suggest using the "Color Test Mode" to verify your settings.</br>
**Note**: There have been issues reported with image sharpening being truned on via the graphic card settings itself outside of D2R. Try turning it off when running botty.
### 2) Supported builds
You char must have a tomb with full tps (make sure when you buy the tomb back with right click it will end up in the previous place) and a belt full with pots of your liking when you start.
#### Soceress
You can put any skills on left and right attack and see if it works out. E.g. Glacial Spike on left attack and Blizzard or right attack.
Adjust the hotkeys in the __custom.ini__ or __param.ini__ for the `[char]` and `[sorceress]` section accordingly. Check out the param.ini section in the Readme for more details on each param.
#### Hammerdin
Your standard Hammerdin with Enigma. Dont think I have to explain much here. Same story as with sorc, set up your skills in the .ini file to what you have in D2R or the other way around.
Your standard Hammerdin with Enigma. Dont think I have to explain much here. Same story as with sorc, set up your skills in the .ini file to what you have in D2R or the other way around. When running more than just pindle or shenk you need to start with a full tomb of tps in your inventory.
### 3) Start Location
Open up D2R and wait till you are at the hero selection screen. Make sure the char you running with is selected and will be in A5 hell when starting a hell game.
### 5) Start Botty
Download the a prebuilt release [here](https://github.com/aeon0/botty/releases). Start `run.exe` in the botty folder, go to D2R window and press the "resume" key. Move to your D2R window and press "f11". You can always force stop botty with f12.
Download the a prebuilt release [here](https://github.com/aeon0/botty/releases). Start `run.exe` in the botty folder. Move to your D2R window and press the start key (default f11). You can always force stop botty with f12.
## Color Test Mode
To check if you graphic settings are good and if the bot would pick up items there is a **Color Test Mode** built in. Start botty and press F10 (Default key). This will open up a (mostly black) window. Start a game in D2R and throw some items of different type on the ground. If you now bring forward the debug window all items should show up with their names while the background is black. If you throw an item on the ground that should be picked up, it will have a red circle.</br>
@@ -73,6 +70,8 @@ resume_key | After starting the exe botty will wait for this keypress to atually
color_checker_key | Pressing this key will start a debug mode to check if the color filtering works with your settings. It also includes the item search and marks items it would pick up with red circles
logger_lvl | Can be any of [info, debug] and determines how much output you see on the command line
randomize_runs | If 0, the order will always be pindle -> eldritch/shenk. If 1 the order will be random.
send_drops_to_discord | If 1 sends your drops to the discord channel "drop-log"
custom_discord_hook | If 1 sends a message about drops to this hook and will update you in case botty got stuck and can not resume
[routes] | Descriptions
--------------------------------|---------------------------------------------
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

+1 -1
View File
@@ -28,7 +28,7 @@ For changelog run: `git log <PREVIOUS_TAG>..HEAD --oneline --decorate`
## Folder Structure
**/**</br>
In the root is docu, param files and development specific stuff such as .gitignore</br>
The root contains docu, param files and development specific stuff such as .gitignore</br>
**assets**</br>
Contains all data for the project that is not source code</br>
+1
View File
@@ -16,3 +16,4 @@ dependencies:
- beautifultable
- zstandard
- pytweening
- requests
+2
View File
@@ -7,6 +7,8 @@ auto_settings_key=f9
color_checker_key=f10
logg_lvl=info
randomize_runs=0
send_drops_to_discord=1
custom_discord_hook=
[routes]
run_pindle=1
+6 -2
View File
@@ -14,7 +14,7 @@ from health_manager import HealthManager
from death_manager import DeathManager
from npc_manager import NpcManager, Npc
from pickit import PickIt
from utils.misc import wait
from utils.misc import wait, send_discord
import keyboard
import threading
import time
@@ -103,7 +103,11 @@ class Bot:
self._timer = time.time()
found, _ = self._template_finder.search_and_wait("D2_LOGO_HS", time_out=70)
if not found:
Logger.error("Something went wrong here, bot is unsure about current location. Exit game and closing down bot.")
Logger.error("Something went wrong here, bot is unsure about current location. Closing down bot.")
if self._config.general["custom_discord_hook"] != "":
send_discord_thread = threading.Thread(target=send_discord, args=("Botty got stuck and can not resume", self._config.general["custom_discord_hook"]))
send_discord_thread.daemon = True
send_discord_thread.start()
self._ui_manager.save_and_exit()
os._exit(1)
self._ui_manager.start_hell_game()
+1 -1
View File
@@ -61,7 +61,7 @@ class IChar:
mouse.click(button="left")
wait(0.02, 0.03)
if self._config.char["slow_walk"]:
wait(0.9, 1.1)
wait(0.8)
def tp_town(self):
keyboard.send(self._char_config["tp"])
+2
View File
@@ -30,6 +30,8 @@ class Config:
"color_checker_key": self._select_val("general", "color_checker_key"),
"logg_lvl": self._select_val("general", "logg_lvl"),
"randomize_runs": bool(int(self._select_val("general", "randomize_runs"))),
"send_drops_to_discord": bool(int(self._select_val("general", "send_drops_to_discord"))),
"custom_discord_hook": self._select_val("general", "custom_discord_hook"),
}
self.routes = {}
+5 -4
View File
@@ -100,11 +100,11 @@ class ItemFinder:
_, mask = cv2.threshold(grayscale, 0, 255, cv2.THRESH_BINARY)
hist = cv2.calcHist([cropped_input], [0, 1, 2], mask, [8, 8, 8], [0, 256, 0, 256, 0, 256])
hist_result = cv2.compareHist(template.hist, hist, cv2.HISTCMP_CORREL)
same_type = hist_result > 0.9 and hist_result is not np.inf
same_type = hist_result > 0.65 and hist_result is not np.inf
if same_type:
result = cv2.matchTemplate(cropped_input, template.data, cv2.TM_CCOEFF_NORMED)
_, max_val, _, max_loc = cv2.minMaxLoc(result)
if max_val > 0.93:
if max_val > 0.89:
if template.blacklist:
item = None
break
@@ -132,9 +132,10 @@ if __name__ == "__main__":
screen = Screen(config.general["monitor"])
item_finder = ItemFinder()
while 1:
# img = cv2.imread("assets/items/flawless_ruby.png")
img = screen.grab()
img = cv2.imread("tt.png")
# img = screen.grab()
item_list = item_finder.search(img)
print(item_list)
for item in item_list:
cv2.circle(img, item.center, 5, (255, 0, 255), thickness=3)
img = cv2.resize(img, None, fx=0.5, fy=0.5)
+13 -1
View File
@@ -7,7 +7,8 @@ from char.i_char import IChar
from logger import Logger
from screen import Screen
from ui_manager import UiManager
import random
import threading
from utils.misc import send_discord
class PickIt:
@@ -54,6 +55,17 @@ class PickIt:
time.sleep(0.1)
mouse.click(button="left")
time.sleep(0.5)
if self._config.general["send_drops_to_discord"]:
send_discord_thread = threading.Thread(target=send_discord, args=(closest_item.name,))
send_discord_thread.daemon = True
send_discord_thread.start()
if self._config.general["custom_discord_hook"] != "":
send_discord_thread = threading.Thread(target=send_discord, args=(closest_item.name, self._config.general["custom_discord_hook"]))
send_discord_thread.daemon = True
send_discord_thread.start()
if self._ui_manager.is_overburdened():
Logger.warning("Inventory full, skipping pickit!")
# TODO: should go back to town and stash stuff then go back to picking up more stuff
+7
View File
@@ -4,8 +4,15 @@ import ctypes
from logger import Logger
import cv2
from typing import List, Tuple
import requests
def send_discord(item_name, url:str = None):
if url is None:
url = "https://discord.com/api/webhooks/908045354061160459/8-HQRLPTHxMlf5VpvScuvNEpLLIe8KHqxgRIk6p17u6LMPvzCCQotT_iGioQHQVU5u_P"
data = {"content": f"Botty just found: {item_name}"}
requests.post(url, json=data)
def wait(min_seconds, max_seconds = None):
if max_seconds is None:
max_seconds = min_seconds
+1 -1
View File
@@ -1 +1 @@
__version__ = '0.2.0'
__version__ = '0.2.1'