Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1404f6f4f | ||
|
|
90cadb4843 | ||
|
|
730b68b2db | ||
|
|
3d36d9286b | ||
|
|
ecf82eeaac | ||
|
|
0a4645769e | ||
|
|
a6d880b2c3 | ||
|
|
f5add914ef | ||
|
|
2cd540e3ec | ||
|
|
2ebbf02cfc | ||
|
|
b3bed8a1fe | ||
|
|
8ef3362cff | ||
|
|
9526d4c56e |
@@ -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.
|
||||
|
||||
[](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 |
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
+1
-1
@@ -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>
|
||||
|
||||
@@ -16,3 +16,4 @@ dependencies:
|
||||
- beautifultable
|
||||
- zstandard
|
||||
- pytweening
|
||||
- requests
|
||||
|
||||
+3
-2
@@ -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
|
||||
@@ -63,6 +65,7 @@ misc_flawless_ruby=1
|
||||
misc_super_healing_potion=1
|
||||
misc_super_mana_potion=1
|
||||
misc_tp_scroll=1
|
||||
misc_gold=0
|
||||
;=====MAGIC=====
|
||||
magic_circlet=1
|
||||
magic_coronet=1
|
||||
@@ -89,7 +92,6 @@ rare_greaves=1
|
||||
rare_hand_scythe=1
|
||||
rare_jewel=1
|
||||
rare_ring=1
|
||||
rare_ring_mail=1
|
||||
rare_runic_talons=1
|
||||
rare_tiara=1
|
||||
rare_war_fist=1
|
||||
@@ -155,7 +157,6 @@ lt_blade_of_ali_baba=1
|
||||
lt_bonehew=1
|
||||
lt_cerebus_bite=1
|
||||
lt_darkforce_spawn=1
|
||||
lt_darkglow=1
|
||||
lt_duriel_shell=1
|
||||
lt_frostburn=1
|
||||
lt_giant_skull=1
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ if os.path.exists(botty_dir):
|
||||
shutil.rmtree(path)
|
||||
shutil.rmtree(botty_dir)
|
||||
|
||||
installer_cmd = f"python -m nuitka --mingw --standalone --onefile --plugin-enable=numpy src/run.py"
|
||||
installer_cmd = f"python -m nuitka --mingw64 --standalone --onefile --plugin-enable=numpy src/run.py"
|
||||
os.system(installer_cmd)
|
||||
|
||||
os.system(f"mkdir {botty_dir}")
|
||||
|
||||
+6
-2
@@ -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
@@ -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"])
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
+19
-4
@@ -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:
|
||||
@@ -46,14 +47,28 @@ class PickIt:
|
||||
closest_item = item
|
||||
x_m, y_m = self._screen.convert_screen_to_monitor(closest_item.center)
|
||||
if closest_item.dist < self._config.ui_pos["item_dist"]:
|
||||
# no need to stash poitions and scrolls
|
||||
if "potion" not in closest_item.name and "tp_scroll" != closest_item.name:
|
||||
# no need to stash potions, scrolls, or gold
|
||||
if (("potion" not in closest_item.name) and ("tp_scroll" != closest_item.name) and ("misc_gold" not in closest_item.name)):
|
||||
found_items = True
|
||||
Logger.info(f"Picking up {closest_item.name}")
|
||||
Logger.info(f"** Looted {closest_item.name}")
|
||||
else:
|
||||
Logger.info(f"Picking up {closest_item.name}")
|
||||
mouse.move(x_m, y_m)
|
||||
time.sleep(0.1)
|
||||
mouse.click(button="left")
|
||||
time.sleep(0.5)
|
||||
|
||||
if found_items and ("rune_" in closest_item.name or "tt_" in closest_item.name):
|
||||
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
|
||||
|
||||
@@ -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/908071105372250213/puaS6gIYqYxTE-TBLAIs6_Qb6ZUwuygSeQfTQkpuXrSag5DPeV2gk0SctOjPy5qMHGeh"
|
||||
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
@@ -1 +1 @@
|
||||
__version__ = '0.2.0'
|
||||
__version__ = '0.2.2'
|
||||
|
||||
Reference in New Issue
Block a user