This repository has been archived by the owner on Jun 3, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 141
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from QuBerto/Qu-Features
Qu features
- Loading branch information
Showing
5 changed files
with
264 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
from .combat.combat import OSRSCombat | ||
from .walkerExample import OSRSWalkingExample | ||
from .woodcutter import OSRSWoodcutter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import utilities.api.locations as loc | ||
from model.osrs.osrs_bot import OSRSBot | ||
from utilities.walker import Walking | ||
|
||
|
||
class OSRSWalkingExample(OSRSBot): | ||
def __init__(self): | ||
self.walk_to = "VARROCK_SQUARE" | ||
super().__init__(bot_title="Walk", description="Walk almost anywhere") | ||
|
||
def create_options(self): | ||
locations = [name for name in vars(loc) if not name.startswith("__")] | ||
self.options_builder.add_dropdown_option("walk_to", "Walk to?", locations) | ||
|
||
def save_options(self, options: dict): | ||
for option in options: | ||
if option == "walk_to": | ||
self.log_msg(f"walk_to: {options[option]}") | ||
self.walk_to = options[option] | ||
self.log_msg("Options set successfully.") | ||
self.options_set = True | ||
|
||
def main_loop(self): | ||
while True: | ||
walker = Walking(self) | ||
if walker.walk_to(self.walk_to): | ||
self.log_msg("Arrived at destination") | ||
self.stop() | ||
self.stop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
LUMBRIDGE_CASTLE = (3221, 3218) | ||
VARROCK_SQUARE = (3210, 3424) | ||
FALADOR_PARK = (2998, 3374) | ||
GRAND_EXCHANGE = (3164, 3487) | ||
EDGEVILLE_BANK = (3093, 3493) | ||
AL_KHARID_PALACE = (3304, 3175) | ||
DRAYNOR_VILLAGE = (3092, 3248) | ||
ARDOUGNE_MARKET = (2655, 3283) | ||
CAMELOT_CASTLE = (2757, 3477) | ||
SEERS_VILLAGE_BANK = (2725, 3491) | ||
YANILLE_AGILITY_DUNGEON_ENTRANCE = (2586, 9436) | ||
BARBARIAN_VILLAGE = (3080, 3424) | ||
TREE_GNOME_STRONGHOLD = (2449, 3420) | ||
PORT_SARIM = (3012, 3196) | ||
CATHERBY_BANK = (2805, 3441) | ||
SHILO_VILLAGE = (2827, 2996) | ||
BRIMHAVEN = (2772, 3234) | ||
FISHING_GUILD = (2597, 3418) | ||
CASTLE_WARS = (2435, 3090) | ||
TAVERLEY = (2888, 3443) | ||
CAMELOT_HERB = (2811, 3462) | ||
ARDOUGNE_HERB = (2673, 3375) | ||
ECTO_HERB = (3604, 3529) | ||
EXPLORERS_RING_HERB = (3057, 3311) | ||
HOSIDIUS_HERB = (1740, 3550) | ||
FARMING_GUILD_HERB = (1240, 3727) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import json | ||
|
||
import requests | ||
|
||
# Example usage | ||
# start_position = (3163, 3474) | ||
# end_position = (2998, 3374) | ||
|
||
# pathfinder = Pathfinder() | ||
# print(pathfinder.get_path(start_position, end_position)) | ||
|
||
API_URL = "https://explv-map.siisiqf.workers.dev/" | ||
|
||
ERROR_MESSAGE_MAPPING = { | ||
"UNMAPPED_REGION": "Unmapped region", | ||
"BLOCKED": "Tile is blocked", | ||
"EXCEEDED_SEARCH_LIMIT": "Exceeded search limit", | ||
"UNREACHABLE": "Unreachable tile", | ||
"NO_WEB_PATH": "No web path", | ||
"INVALID_CREDENTIALS": "Invalid credentials", | ||
"RATE_LIMIT_EXCEEDED": "Rate limit exceeded", | ||
"NO_RESPONSE_FROM_SERVER": "No response from server", | ||
"UNKNOWN": "Unknown", | ||
} | ||
|
||
|
||
class Pathfinder: | ||
def __init__(self): | ||
pass | ||
|
||
@staticmethod | ||
def get_path(start, end): | ||
start_z = start[2] if len(start) > 2 else 0 | ||
end_z = end[2] if len(end) > 2 else 0 | ||
payload = {"start": {"x": start[0], "y": start[1], "z": start_z}, "end": {"x": end[0], "y": end[1], "z": end_z}, "player": {"members": True}} | ||
|
||
headers = { | ||
"Content-Type": "application/json", | ||
"Origin": "https://explv.github.io", | ||
} | ||
response = requests.post(API_URL, data=json.dumps(payload), headers=headers) | ||
if response.status_code == 200: | ||
data = response.json() | ||
if data["pathStatus"] != "SUCCESS": | ||
error_message = ERROR_MESSAGE_MAPPING.get(data["pathStatus"], "Unknown error") | ||
return {"status": "error", "data": None, "error": error_message} | ||
else: | ||
path = data["path"] | ||
path_positions = [(pos["x"], pos["y"], pos["z"]) for pos in path] | ||
return {"status": "success", "data": path_positions, "error": None} | ||
else: | ||
return {"status": "error", "data": None, "error": "Error occurred while communicating with the server"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
import math | ||
from typing import List | ||
|
||
import utilities.api.locations as loc | ||
from utilities.api.morg_http_client import MorgHTTPSocket | ||
from utilities.api.pathfinding_api import Pathfinder | ||
|
||
|
||
class Walking: | ||
DEGREESPERYAW: float = 360 / 2048 | ||
TILES_PIXELS = 4 | ||
|
||
def __init__(self, runeLiteBot): | ||
self.bot = runeLiteBot | ||
self.api_m = MorgHTTPSocket() | ||
self.run_bool = False | ||
|
||
def update_run_energy(self): | ||
self.run_energy = self.api_m.get_run_energy() | ||
|
||
def update_position(self): | ||
self.position = self.api_m.get_player_position() | ||
|
||
def update_camera_angle(self) -> None: | ||
self.camera_angle = self.api_m.get_camera_position().get("yaw") | ||
|
||
def compute_tiles(self, new_x: int, new_y: int) -> List[float]: | ||
"""Returns the range to click from the minimap center in amount of tiles.""" | ||
# Get live camera data. | ||
self.update_camera_angle() | ||
# Account for anticlockwise OSRS minimap. | ||
degrees = 360 - self.DEGREESPERYAW * self.camera_angle | ||
# Turn degrees into pi-radians. | ||
theta = math.radians(degrees) | ||
# Turn position difference into pixels difference. | ||
self.update_position() | ||
x_reg = (new_x - self.position[0]) * self.TILES_PIXELS | ||
y_reg = (self.position[1] - new_y) * self.TILES_PIXELS | ||
# Formulas to compute norm of a vector in a rotated coordinate system. | ||
tiles_x = x_reg * math.cos(theta) + y_reg * math.sin(theta) | ||
tiles_y = -x_reg * math.sin(theta) + y_reg * math.cos(theta) | ||
return [round(tiles_x, 1), round(tiles_y, 1)] | ||
|
||
def change_position(self, new_pos: List[int]) -> None: | ||
"""Clicks the minimap to change position""" | ||
self.update_position() | ||
tiles = self.compute_tiles(new_pos[0], new_pos[1]) | ||
if tiles != []: | ||
minimap_center = self.bot.win.minimap.get_center() | ||
new_x = round(minimap_center[0] + tiles[0] - 1) | ||
new_y = round(minimap_center[1] + tiles[1] - 1) | ||
self.bot.mouse.move_to([new_x, new_y], mouseSpeed="fast") | ||
self.bot.mouse.click() | ||
while abs(self.position[0] - new_pos[0]) > 5 or abs(self.position[1] - new_pos[1]) > 5: | ||
self.update_position() | ||
continue | ||
|
||
def get_target_pos(self, path) -> List[int]: | ||
"""Returns furthest possible coord.""" | ||
self.update_position() | ||
idx = next(i for i in range(len(path) - 1, -1, -1) if (abs(path[i][0] - self.position[0]) <= 12 and abs(path[i][1] - self.position[1]) <= 12)) | ||
self.bot.log_msg(f"Walking progress: {idx}/{len(path)}") | ||
new_pos = path[idx] | ||
return new_pos | ||
|
||
def turn_run_on(self) -> None: | ||
"""Turns on run energy.""" | ||
self.bot.mouse.move_to(self.bot.win.run_orb.random_point(), duration=0.2) | ||
self.bot.mouse.click() | ||
|
||
def check_if_at_destination(self, area_destination) -> bool: | ||
"""Returns whether the player reached his destination.""" | ||
self.update_position() | ||
|
||
bool_x = self.position[0] in range(area_destination[0] - 1, area_destination[2] + 1) | ||
bool_y = self.position[1] in range(area_destination[1] - 1, area_destination[3] + 1) | ||
|
||
return bool_x and bool_y | ||
|
||
def handle_running(self) -> None: | ||
"""Turns on run if run energy is higher than 60.""" | ||
# If run is off and run energy is larger than 60, turn on run. | ||
self.run_energy = self.api_m.get_run_energy() | ||
if self.run_energy < 5000 or self.run_energy == 10000: | ||
self.run_bool = False | ||
if self.run_energy > 6000 and self.run_bool is False: | ||
self.turn_run_on() | ||
self.run_bool = True | ||
|
||
def walk(self, path, area_destination) -> None: | ||
"""Walks a path by clicking on the minimap""" | ||
while True: | ||
# Turn on running if needed | ||
self.handle_running() | ||
# Get live position. | ||
new_pos = self.get_target_pos(path) | ||
if self.check_if_at_destination(area_destination): | ||
self.bot.mouse.move_to(self.bot.win.game_view.get_center(), mouseSpeed="fastest") | ||
if self.bot.mouseover_text("Walk"): | ||
self.bot.mouse.click() | ||
return True | ||
self.change_position(new_pos) | ||
if new_pos == path[-1]: | ||
while not self.check_if_at_destination(area_destination): | ||
self.update_position() | ||
continue | ||
|
||
def walk_to(self, end_location): | ||
current_location = self.api_m.get_player_position() | ||
new_current_position = [current_location[0], current_location[1]] | ||
if isinstance(end_location, str): | ||
end_coordinates = getattr(loc, end_location) | ||
new_end_coordinates = [end_coordinates[0] - 1, end_coordinates[1] - 1, end_coordinates[0] + 1, end_coordinates[1] + 1] | ||
if isinstance(end_location, list): | ||
end_coordinates = end_location | ||
new_end_coordinates = [end_coordinates[0] - 1, end_coordinates[1] - 1, end_coordinates[0] + 1, end_coordinates[1] + 1] | ||
if isinstance(end_location, tuple): | ||
end_coordinates = end_location | ||
new_end_coordinates = [end_coordinates[0] - 1, end_coordinates[1] - 1, end_coordinates[0] + 1, end_coordinates[1] + 1] | ||
path = [] | ||
while path == []: | ||
path = self.api_path(new_current_position, end_coordinates) | ||
if path == []: | ||
self.bot.take_break(4, 5) | ||
|
||
self.walk(path, new_end_coordinates) | ||
|
||
def api_path(self, start_coordinates, end_coordinates): | ||
pathfinder = Pathfinder() | ||
steps = pathfinder.get_path(start_coordinates, end_coordinates) | ||
|
||
if steps.get("status") == "success": | ||
processed_data = [[item[0], item[1]] for item in steps.get("data")] | ||
waypoints = self.add_waypoints(processed_data) | ||
return waypoints | ||
return [] | ||
|
||
def distance(self, p1, p2): | ||
return math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) | ||
|
||
def add_waypoints(self, coordinates): | ||
new_coordinates = [coordinates[0]] # Start with the first coordinate | ||
for i in range(len(coordinates) - 1): | ||
p1 = coordinates[i] | ||
p2 = coordinates[i + 1] | ||
d = self.distance(p1, p2) # Calculate distance between consecutive waypoints | ||
|
||
if d > 10: | ||
num_waypoints = math.ceil(d / 11) # Calculate number of waypoints needed | ||
dx = (p2[0] - p1[0]) / num_waypoints | ||
dy = (p2[1] - p1[1]) / num_waypoints | ||
for j in range(1, num_waypoints): | ||
new_coordinates.append([round(p1[0] + j * dx), round(p1[1] + j * dy)]) # Add intermediate waypoints | ||
new_coordinates.append(p2) # Add the next waypoint | ||
|
||
return new_coordinates |