Gambling by @RB-Development (#445)
This branch will detect if stash is full of gold. Afterwards the gambling functionality (currently only in act 4 implemented) will be called. The bot will gamble for specific items (determined in params.ini) until no gold is left. He will check for properties specified in pickit.ini and sell not matching items. Supported items are: ring, amulet, circlet, coronet, talon Leverages recent advanced pickit PR.
@@ -127,6 +127,7 @@ run_shenk=0
|
||||
| id_items | Will identify items at cain before stashing them. Cain must be rescued for this to work.|
|
||||
| open_chests | Open up chests in some places. E.g. on dead ends of arcane. Note: currently bad runtime. |
|
||||
| fill_shared_stash_first | Fill stash tabs starting from right to left, filling personal stash last |
|
||||
| gamble_items | List of items to gamble when stash fills with gold. Leave blank to disable. Supported items currently include circlet, ring, coronet, talon, amulet
|
||||
|
||||
### Builds
|
||||
| [sorceress] | Descriptions |
|
||||
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
@@ -89,6 +89,8 @@ always_repair=0
|
||||
id_items=1
|
||||
open_chests=1
|
||||
fill_shared_stash_first=0
|
||||
; to gamble, add any/all of the following: circlet, ring, coronet, talon, amulet
|
||||
gamble_items=
|
||||
|
||||
; ===========================
|
||||
; ==== Builds: Sorceress ====
|
||||
|
||||
@@ -298,6 +298,19 @@ class Bot:
|
||||
if not self._curr_loc:
|
||||
return self.trigger_or_stop("end_game", failed=True)
|
||||
|
||||
# Check if gambling is needed
|
||||
gambling = self._ui_manager.gambling_needed()
|
||||
if gambling:
|
||||
for x in range (4):
|
||||
self._curr_loc = self._town_manager.gamble(self._curr_loc)
|
||||
self._ui_manager.gamble(self._item_finder)
|
||||
if (x ==3):
|
||||
self._curr_loc = self._town_manager.stash (self._curr_loc)
|
||||
else:
|
||||
self._curr_loc = self._town_manager.stash (self._curr_loc, gamble=gambling)
|
||||
|
||||
self._ui_manager.set__gold_full (False)
|
||||
|
||||
# Start a new run
|
||||
started_run = False
|
||||
for key in self._do_runs:
|
||||
|
||||
@@ -28,6 +28,7 @@ class Config:
|
||||
# config data
|
||||
general = {}
|
||||
advanced_options = {}
|
||||
gamble = {}
|
||||
ui_roi = {}
|
||||
ui_pos = {}
|
||||
dclone = {}
|
||||
@@ -241,8 +242,8 @@ class Config:
|
||||
"atk_len_cs_trashmobs": float(Config._select_val("char", "atk_len_cs_trashmobs")),
|
||||
"kill_cs_trash": float(Config._select_val("char", "kill_cs_trash")),
|
||||
"always_repair": bool(int(Config._select_val("char", "always_repair"))),
|
||||
"gamble_items": Config._select_val("char", "gamble_items").replace(" ","").split(","),
|
||||
}
|
||||
|
||||
# Sorc base config
|
||||
sorc_base_cfg = dict(Config._config["sorceress"])
|
||||
if "sorceress" in Config._custom:
|
||||
|
||||
@@ -166,6 +166,10 @@ class NpcManager:
|
||||
"trade": {
|
||||
"white": color_filter(self._template_finder.get_template("TRADE"), self._config.colors["white"])[1],
|
||||
"blue": color_filter(self._template_finder.get_template("TRADE_BLUE"), self._config.colors["blue"])[1],
|
||||
},
|
||||
"gamble": {
|
||||
"white": color_filter(self._template_finder.get_template("GAMBLE"), self._config.colors["white"])[1],
|
||||
"blue": color_filter(self._template_finder.get_template("GAMBLE_BLUE"), self._config.colors["blue"])[1],
|
||||
}
|
||||
},
|
||||
"roi": [337, 188, (733-337), (622-188)],
|
||||
|
||||
@@ -28,12 +28,7 @@ class TemplateFinder:
|
||||
to find these assets within another image
|
||||
IMPORTANT: This method must be thread safe!
|
||||
"""
|
||||
def __init__(
|
||||
self,
|
||||
screen: Screen,
|
||||
template_pathes: list[str] = ["assets\\templates", "assets\\npc", "assets\\item_properties", "assets\\chests"],
|
||||
save_last_res: bool = False
|
||||
):
|
||||
def __init__(self, screen: Screen, template_pathes: list[str] = ["assets\\templates", "assets\\npc", "assets\\item_properties", "assets\\chests", "assets\\gamble"], save_last_res: bool = False):
|
||||
self._screen = screen
|
||||
self._config = Config()
|
||||
self._save_last_res = save_last_res
|
||||
|
||||
@@ -22,6 +22,7 @@ class A4(IAct):
|
||||
def can_resurrect(self) -> bool: return True
|
||||
def can_buy_pots(self) -> bool: return True
|
||||
def can_identify(self) -> bool: return True
|
||||
def can_gamble(self) -> bool: return True
|
||||
def can_heal(self) -> bool: return True
|
||||
def can_stash(self) -> bool: return True
|
||||
def can_trade_and_repair(self) -> bool: return True
|
||||
@@ -53,6 +54,13 @@ class A4(IAct):
|
||||
self._npc_manager.press_npc_btn(Npc.CAIN, "identify")
|
||||
return Location.A4_TYRAEL_STASH
|
||||
return False
|
||||
|
||||
def gamble (self, curr_loc: Location) -> Union[Location, bool]:
|
||||
if not self._pather.traverse_nodes((curr_loc, Location.A4_JAMELLA), self._char, force_move=True): return False
|
||||
if self._npc_manager.open_npc_menu(Npc.JAMELLA):
|
||||
self._npc_manager.press_npc_btn(Npc.JAMELLA, "gamble")
|
||||
return Location.A4_JAMELLA
|
||||
return False
|
||||
|
||||
def open_trade_menu(self, curr_loc: Location) -> Union[Location, bool]:
|
||||
if not self._pather.traverse_nodes((curr_loc, Location.A4_JAMELLA), self._char, force_move=True): return False
|
||||
|
||||
@@ -22,6 +22,7 @@ class IAct:
|
||||
def can_trade_and_repair(self) -> bool: return False
|
||||
# Is merc resurrection implemented for this Town?
|
||||
def can_identify(self) -> bool: return False
|
||||
def can_gamble (self) -> bool: return False
|
||||
# If any of the above functions return True for the Town, the respective method must be implemented
|
||||
def open_trade_menu(self, curr_loc: Location) -> Union[Location, bool]: return False
|
||||
def heal(self, curr_loc: Location) -> Union[Location, bool]: return False
|
||||
@@ -29,3 +30,4 @@ class IAct:
|
||||
def open_stash(self, curr_loc: Location) -> Union[Location, bool]: return False
|
||||
def open_trade_and_repair_menu(self, curr_loc: Location) -> Union[Location, bool]: return False
|
||||
def identify(self, curr_loc: Location) -> Union[Location, bool]: return False
|
||||
def gamble (self, curr_loc: Location) -> Union[Location, bool]: return False
|
||||
|
||||
@@ -125,8 +125,18 @@ class TownManager:
|
||||
new_loc = self.go_to_act(5, curr_loc)
|
||||
if not new_loc: return False
|
||||
return self._acts[Location.A5_TOWN_START].identify(new_loc)
|
||||
|
||||
def gamble (self, curr_loc: Location) -> Union[Location, bool]:
|
||||
curr_act = TownManager.get_act_from_location(curr_loc)
|
||||
if curr_act is None: return False
|
||||
# check if we can Identify in current act
|
||||
if self._acts[curr_act].can_gamble():
|
||||
return self._acts[curr_act].gamble(curr_loc)
|
||||
new_loc = self.go_to_act(4, curr_loc)
|
||||
if not new_loc: return False
|
||||
return self._acts[Location.A4_TOWN_START].gamble(new_loc)
|
||||
|
||||
def stash(self, curr_loc: Location) -> Union[Location, bool]:
|
||||
def stash(self, curr_loc: Location, gamble=False) -> Union[Location, bool]:
|
||||
curr_act = TownManager.get_act_from_location(curr_loc)
|
||||
if curr_act is None: return False
|
||||
# check if we can stash in current act
|
||||
@@ -134,7 +144,7 @@ class TownManager:
|
||||
new_loc = self._acts[curr_act].open_stash(curr_loc)
|
||||
if not new_loc: return False
|
||||
wait(1.0)
|
||||
self._ui_manager.stash_all_items(self._config.char["num_loot_columns"], self._item_finder)
|
||||
self._ui_manager.stash_all_items(self._config.char["num_loot_columns"], self._item_finder, gamble)
|
||||
return new_loc
|
||||
new_loc = self.go_to_act(5, curr_loc)
|
||||
if not new_loc: return False
|
||||
|
||||
@@ -28,6 +28,8 @@ class UiManager():
|
||||
self._messenger = Messenger()
|
||||
self._game_stats = game_stats
|
||||
self._screen = screen
|
||||
self._gold_full = False
|
||||
self._gambling_round = 1
|
||||
self._curr_stash = {
|
||||
"items": 3 if self._config.char["fill_shared_stash_first"] else 0,
|
||||
"gold": 0
|
||||
@@ -240,14 +242,14 @@ class UiManager():
|
||||
center_pos = (int(slot[0] + (slot_width // 2)), int(slot[1] + (slot_height // 2)))
|
||||
return center_pos, slot_img
|
||||
|
||||
def _inventory_has_items(self, img, num_loot_columns: int) -> bool:
|
||||
def _inventory_has_items(self, img, num_loot_columns: int, num_ignore_columns=0) -> bool:
|
||||
"""
|
||||
Check if Inventory has any items
|
||||
:param img: Img from screen.grab() with inventory open
|
||||
:param num_loot_columns: Number of columns to check from left
|
||||
:return: Bool if inventory still has items or not
|
||||
"""
|
||||
for column, row in itertools.product(range(num_loot_columns), range(4)):
|
||||
for column, row in itertools.product(range(num_ignore_columns, num_loot_columns), range(4)):
|
||||
_, slot_img = self.get_slot_pos_and_img(self._config, img, column, row)
|
||||
if self._slot_has_item(slot_img):
|
||||
return True
|
||||
@@ -372,7 +374,7 @@ class UiManager():
|
||||
mouse.click(button="left")
|
||||
wait(0.3, 0.4)
|
||||
|
||||
def stash_all_items(self, num_loot_columns: int, item_finder: ItemFinder):
|
||||
def stash_all_items(self, num_loot_columns: int, item_finder: ItemFinder, gamble = False):
|
||||
"""
|
||||
Stashing all items in inventory. Stash UI must be open when calling the function.
|
||||
:param num_loot_columns: Number of columns used for loot from left
|
||||
@@ -387,41 +389,51 @@ class UiManager():
|
||||
Logger.error("Could not determine to be in stash menu. Continue...")
|
||||
return
|
||||
Logger.debug("Found inventory gold btn")
|
||||
# stash gold
|
||||
if self._config.char["stash_gold"]:
|
||||
inventory_no_gold = self._template_finder.search("INVENTORY_NO_GOLD", self._screen.grab(), roi=self._config.ui_roi["inventory_gold"], threshold=0.83)
|
||||
if inventory_no_gold.valid:
|
||||
Logger.debug("Skipping gold stashing")
|
||||
else:
|
||||
Logger.debug("Stashing gold")
|
||||
self._move_to_stash_tab(min(3, self._curr_stash["gold"]))
|
||||
mouse.move(*gold_btn.center, randomize=4)
|
||||
wait(0.1, 0.15)
|
||||
mouse.press(button="left")
|
||||
wait(0.25, 0.35)
|
||||
mouse.release(button="left")
|
||||
wait(0.4, 0.6)
|
||||
keyboard.send("enter") #if stash already full of gold just nothing happens -> gold stays on char -> no popup window
|
||||
wait(1.0, 1.2)
|
||||
# move cursor away from button to interfere with screen grab
|
||||
mouse.move(-120, 0, absolute=False, randomize=15)
|
||||
if not gamble:
|
||||
# stash gold
|
||||
if self._config.char["stash_gold"]:
|
||||
inventory_no_gold = self._template_finder.search("INVENTORY_NO_GOLD", self._screen.grab(), roi=self._config.ui_roi["inventory_gold"], threshold=0.83)
|
||||
if not inventory_no_gold.valid:
|
||||
Logger.info("Stash tab is full of gold, selecting next stash tab.")
|
||||
self._curr_stash["gold"] += 1
|
||||
if self._config.general["info_screenshots"]:
|
||||
cv2.imwrite("./info_screenshots/info_gold_stash_full_" + time.strftime("%Y%m%d_%H%M%S") + ".png", self._screen.grab())
|
||||
if self._curr_stash["gold"] > 3:
|
||||
# turn off gold pickup
|
||||
self._config.turn_off_goldpickup()
|
||||
# inform user about it
|
||||
Logger.info("All stash tabs and character are full of gold, turn of gold pickup")
|
||||
if self._config.general["custom_message_hook"]:
|
||||
self._messenger.send_gold()
|
||||
else:
|
||||
# move to next stash
|
||||
wait(0.5, 0.6)
|
||||
return self.stash_all_items(num_loot_columns, item_finder)
|
||||
if inventory_no_gold.valid:
|
||||
Logger.debug("Skipping gold stashing")
|
||||
else:
|
||||
Logger.debug("Stashing gold")
|
||||
self._move_to_stash_tab(min(3, self._curr_stash["gold"]))
|
||||
mouse.move(*gold_btn.center, randomize=4)
|
||||
wait(0.1, 0.15)
|
||||
mouse.press(button="left")
|
||||
wait(0.25, 0.35)
|
||||
mouse.release(button="left")
|
||||
wait(0.4, 0.6)
|
||||
keyboard.send("enter") #if stash already full of gold just nothing happens -> gold stays on char -> no popup window
|
||||
wait(1.0, 1.2)
|
||||
# move cursor away from button to interfere with screen grab
|
||||
mouse.move(-120, 0, absolute=False, randomize=15)
|
||||
inventory_no_gold = self._template_finder.search("INVENTORY_NO_GOLD", self._screen.grab(), roi=self._config.ui_roi["inventory_gold"], threshold=0.83)
|
||||
if not inventory_no_gold.valid:
|
||||
Logger.info("Stash tab is full of gold, selecting next stash tab.")
|
||||
self._curr_stash["gold"] += 1
|
||||
if self._config.general["info_screenshots"]:
|
||||
cv2.imwrite("./info_screenshots/info_gold_stash_full_" + time.strftime("%Y%m%d_%H%M%S") + ".png", self._screen.grab())
|
||||
if self._curr_stash["gold"] > 3:
|
||||
#decide if gold pickup should be disabled or gambling is active
|
||||
if (self._config.char["gamble_items"]):
|
||||
self._gold_full = True
|
||||
else:
|
||||
# turn off gold pickup
|
||||
self._config.char["stash_gold"] = False
|
||||
self._config.items["misc_gold"].pickit_type = 0
|
||||
item_finder.update_items_to_pick(self._config)
|
||||
# inform user about it
|
||||
msg = "All stash tabs and character are full of gold, turn of gold pickup"
|
||||
Logger.info(msg)
|
||||
if self._config.general["custom_message_hook"]:
|
||||
self._messenger.send(msg=f"{self._config.general['name']}: {msg}")
|
||||
else:
|
||||
# move to next stash
|
||||
wait(0.5, 0.6)
|
||||
return self.stash_all_items(num_loot_columns, item_finder)
|
||||
else:
|
||||
self.transfer_shared_to_private_gold (self._gambling_round)
|
||||
# stash stuff
|
||||
self._move_to_stash_tab(self._curr_stash["items"])
|
||||
center_m = self._screen.convert_abs_to_monitor((0, 0))
|
||||
@@ -502,6 +514,34 @@ class UiManager():
|
||||
wait(0.4, 0.5)
|
||||
keyboard.send("esc")
|
||||
|
||||
def transfer_shared_to_private_gold (self, count: int):
|
||||
for x in range (3):
|
||||
self._move_to_stash_tab (count)
|
||||
stash_gold_btn = self._template_finder.search("INVENTORY_GOLD_BTN", self._screen.grab(), roi=self._config.ui_roi["gold_btn_stash"], threshold=0.83)
|
||||
if stash_gold_btn.valid:
|
||||
x,y = self._screen.convert_screen_to_monitor(stash_gold_btn.center)
|
||||
mouse.move(x, y, randomize=4)
|
||||
wait (0.4, 0.5)
|
||||
mouse.press(button="left")
|
||||
wait (0.1, 0.15)
|
||||
mouse.release(button="left")
|
||||
wait (0.1, 0.15)
|
||||
keyboard.send ("Enter")
|
||||
wait (0.1, 0.15)
|
||||
self._move_to_stash_tab (0)
|
||||
inventory_gold_btn = self._template_finder.search("INVENTORY_GOLD_BTN", self._screen.grab(), roi=self._config.ui_roi["gold_btn"], threshold=0.83)
|
||||
if inventory_gold_btn.valid:
|
||||
x,y = self._screen.convert_screen_to_monitor(inventory_gold_btn.center)
|
||||
mouse.move(x, y, randomize=4)
|
||||
wait (0.4, 0.5)
|
||||
mouse.press(button="left")
|
||||
wait (0.1, 0.15)
|
||||
mouse.release(button="left")
|
||||
wait (0.1, 0.15)
|
||||
keyboard.send ("Enter")
|
||||
wait (0.1, 0.15)
|
||||
self._gambling_round += 1
|
||||
|
||||
def should_stash(self, num_loot_columns: int):
|
||||
"""
|
||||
Check if there are items that need to be stashed in the inventory
|
||||
@@ -596,6 +636,69 @@ class UiManager():
|
||||
use_grayscale=True)
|
||||
return template_match.valid
|
||||
|
||||
def gambling_needed(self) -> bool:
|
||||
return self._gold_full
|
||||
|
||||
def set__gold_full (self, bool: bool):
|
||||
self._gold_full = bool
|
||||
self._gambling_round = 1
|
||||
|
||||
def gamble(self, item_finder: ItemFinder):
|
||||
gold = True
|
||||
gamble_on = True
|
||||
if self._config.char["num_loot_columns"]%2==0:
|
||||
ignore_columns = self._config.char["num_loot_columns"]-1
|
||||
else:
|
||||
ignore_columns = self._config.char["num_loot_columns"]-2
|
||||
template_match = self._template_finder.search_and_wait("REFRESH", threshold=0.79, time_out=4)
|
||||
if template_match.valid:
|
||||
#Gambling window is open. Starting to spent some coins
|
||||
while (gamble_on and gold):
|
||||
if (self._inventory_has_items (self._screen.grab(),self._config.char["num_loot_columns"], ignore_columns) and self._inventory_has_items (self._screen.grab(),2)):
|
||||
gamble_on = False
|
||||
self.close_vendor_screen ()
|
||||
break
|
||||
for item in self._config.char["gamble_items"]:
|
||||
template_match_item = self._template_finder.search (item.upper(), self._screen.grab(), roi=self._config.ui_roi["vendor_stash"], normalize_monitor=True)
|
||||
while not template_match_item.valid:
|
||||
#Refresh gambling screen
|
||||
template_match = self._template_finder.search ("REFRESH", self._screen.grab(), normalize_monitor=True)
|
||||
if (template_match.valid):
|
||||
mouse.move(*template_match.center, randomize=12, delay_factor=[1.0, 1.5])
|
||||
wait(0.1, 0.15)
|
||||
mouse.click(button="left")
|
||||
wait(0.1, 0.15)
|
||||
template_match_item = self._template_finder.search (item.upper(), self._screen.grab(), roi=self._config.ui_roi["vendor_stash"], normalize_monitor=True)
|
||||
#item found in gambling menu
|
||||
mouse.move(*template_match_item.center, randomize=12, delay_factor=[1.0, 1.5])
|
||||
wait(0.1, 0.15)
|
||||
mouse.click(button="right")
|
||||
wait(0.1, 0.15)
|
||||
template_match = self._template_finder.search ("no_gold".upper(), self._screen.grab(), threshold= 0.90)
|
||||
#check if gold is av
|
||||
if template_match.valid:
|
||||
gold = False
|
||||
self.close_vendor_screen ()
|
||||
break
|
||||
for column, row in itertools.product(range(self._config.char["num_loot_columns"]), range(4)):
|
||||
img = self._screen.grab()
|
||||
slot_pos, slot_img = self.get_slot_pos_and_img(self._config, img, column, row)
|
||||
if self._slot_has_item(slot_img):
|
||||
x_m, y_m = self._screen.convert_screen_to_monitor(slot_pos)
|
||||
mouse.move(x_m, y_m, randomize=10, delay_factor=[1.0, 1.3])
|
||||
# check item again and discard it or stash it
|
||||
wait(1.2, 1.4)
|
||||
hovered_item = self._screen.grab()
|
||||
if not self._keep_item(item_finder, hovered_item):
|
||||
keyboard.send('ctrl', do_release=False)
|
||||
wait(0.1, 0.15)
|
||||
mouse.click (button="left")
|
||||
wait(0.1, 0.15)
|
||||
keyboard.send('ctrl', do_press=False)
|
||||
#Stashing needed
|
||||
else:
|
||||
Logger.warning("gambling failed")
|
||||
|
||||
def enable_no_pickup(self) -> bool:
|
||||
"""
|
||||
Checks the best match between enabled and disabled an retrys if already set.
|
||||
@@ -658,4 +761,4 @@ if __name__ == "__main__":
|
||||
template_finder = TemplateFinder(screen)
|
||||
item_finder = ItemFinder()
|
||||
ui_manager = UiManager(screen, template_finder, game_stats)
|
||||
ui_manager.stash_all_items(5, item_finder)
|
||||
ui_manager.gamble (item_finder)
|
||||