Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# TerBot

TerBot is a **Shitty** botting tool for [territorial.io](https://territorial.io) which puts a bunch of bots in your game. It's not very efficient because it uses Selenium, which takes up a lot of resources. But it kinda gets the job done. At 25 stars, I might try to recode it to communicate with the game's WebSocket server instead of using Selenium windows for each client, which will make it a lot more efficient and allow people to run basically an infinite number of bots.
TerBot is a **Shitty** botting tool for [territorial.io](https://territorial.io) which puts a bunch of bots in your game. It just commands bots to join a game, but doesn't actually play the game. It's not very efficient because it uses Selenium, which takes up a lot of resources. But it kinda gets the job done. At 25 stars, I might try to recode it to communicate with the game's WebSocket server instead of using Selenium windows for each client, which will make it a lot more efficient and allow people to run basically an infinite number of bots.

## Features

Expand Down
174 changes: 87 additions & 87 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,133 +6,133 @@
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from colorama import init, Fore, Style

init(autoreset=True)

# Silence unnecessary logs
logging.getLogger('selenium').setLevel(logging.WARNING)
chrome_logger = logging.getLogger('chromedriver')
chrome_logger.setLevel(logging.ERROR)

active_drivers = []
cleanup_done = False

def cleanup():
global cleanup_done
if not cleanup_done:
print(f"{Fore.YELLOW}Cleanup:{Style.RESET_ALL} Closing all browser instances...")
for driver in active_drivers:
try:
driver.quit()
except:
pass
print(f"{Fore.GREEN}Cleanup:{Style.RESET_ALL} All browser instances closed.")
cleanup_done = True

def load_proxies(filename='proxies.txt'):
with open(filename, 'r') as file:
return [line.strip() for line in file if line.strip()]
print(f"\n{Fore.YELLOW}Cleanup:{Style.RESET_ALL} Closing all browser instances...")
for driver in active_drivers:
try:
driver.quit()
except:
pass
print(f"{Fore.GREEN}Cleanup:{Style.RESET_ALL} Done.")

def setup_chrome(proxy=None):
options = Options()
options.add_experimental_option("detach", True)
if proxy:
options.add_argument(f"--proxy-server=http://{proxy}")
options.add_argument("--headless")

options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--disable-extensions")
options.add_argument("--disable-popup-blocking")
options.add_experimental_option('excludeSwitches', ['enable-logging'])
return options

def launch_browser(proxy=None, username="TerBot.bar"):
def enable_visual_mouse(driver):
script = """
var cursor = document.createElement('div');
cursor.id = 'selenium-mouse';
cursor.style.position = 'absolute';
cursor.style.zIndex = '9999';
cursor.style.width = '10px';
cursor.style.height = '10px';
cursor.style.background = 'red';
cursor.style.borderRadius = '50%';
cursor.style.pointerEvents = 'none';
document.body.appendChild(cursor);

document.addEventListener('mousedown', function(e) {
cursor.style.left = e.pageX - 5 + 'px';
cursor.style.top = e.pageY - 5 + 'px';
cursor.style.background = 'yellow';
setTimeout(() => { cursor.style.background = 'red'; }, 200);
});
"""
driver.execute_script(script)

def launch_and_ready(username, proxy=None):
options = setup_chrome(proxy)
driver = webdriver.Chrome(options=options)
active_drivers.append(driver)

# Standardize window size for coordinate accuracy
driver.set_window_size(1336, 768)
enable_visual_mouse(driver)
driver.get("https://territorial.io")

driver.find_element(By.ID, "inputUsername").send_keys(username)
print(f"{Fore.GREEN}Info:{Style.RESET_ALL} Set username '{username}' in {threading.current_thread().name}")

driver.find_element(By.CSS_SELECTOR, "button[style*='background-color: rgba(0, 70, 0, 0.85);']").click()
print(f"{Fore.GREEN}Info:{Style.RESET_ALL} Clicked Multiplayer in {threading.current_thread().name}")
time.sleep(7.5)

return driver

def select_game(driver, game_id):
game_coords = {
1: (450, 200), 2: (600, 200), 3: (750, 200),
4: (900, 200), 5: (450, 300), 6: (600, 300), 7: (700,300)
}
try:
wait = WebDriverWait(driver, 15)

# 1. Enter Username
user_input = wait.until(EC.presence_of_element_located((
By.CSS_SELECTOR, "input#input0, input[placeholder*='Username']"
)))
user_input.clear()
user_input.send_keys(username)
print(f"{Fore.CYAN}[{username}]{Style.RESET_ALL} Username set.")

# 2. Click Multiplayer
# This button uses a specific green color in the style attribute
multiplayer_btn = wait.until(EC.element_to_be_clickable((
By.CSS_SELECTOR, "button[style*='rgba(0, 70, 0, 0.85)']"
)))
multiplayer_btn.click()
print(f"{Fore.CYAN}[{username}]{Style.RESET_ALL} Entered Multiplayer lobby.")

# Small sleep to let the canvas load the lobby UI
time.sleep(3)

driver.find_element(By.TAG_NAME, "body").click()
time.sleep(0.5)

# Send the Space key
ActionChains(driver).send_keys(Keys.SPACE).perform()
print(f"{Fore.GREEN}Info:{Style.RESET_ALL} Sent Spacebar 'Ready' signal.")

if game_id in game_coords:
x, y = game_coords[game_id]
ActionChains(driver).move_by_offset(x, y).click().perform()
print(f"{Fore.GREEN}Info:{Style.RESET_ALL} Joined game in {threading.current_thread().name}")
else:
print(f"{Fore.RED}Error:{Style.RESET_ALL} Invalid game ID in {threading.current_thread().name}")
return driver
except Exception as e:
print(f"{Fore.RED}Error with {username}:{Style.RESET_ALL} {e}")
return None

def main():
clan_tag = input("Enter clan tag for bots (optional, press Enter to skip): ").strip()
clan_tag = input("Enter clan tag (optional): ").strip()
base_name = f"[{clan_tag}] TerBot" if clan_tag else "TerBot"

username = f"[{clan_tag}] TerBot" if clan_tag else "TerBot"

while True:
try:
bot_count = int(input("Number of bot instances to run: "))
if bot_count > 0:
break
print("Enter a positive number.")
except ValueError:
print("Invalid input. Enter a number.")

use_proxies = input("Use proxies? (y/n): ").strip().lower() == 'y'

drivers = []
threads = []
try:
count = int(input("How many bots? "))
except:
count = 1

if use_proxies:
proxies = load_proxies()
if bot_count > len(proxies):
print(f"{Fore.RED}Error:{Style.RESET_ALL} Not enough proxies for {bot_count} bots.")
return
for i in range(bot_count):
t = threading.Thread(target=lambda: drivers.append(launch_browser(proxies[i], username)), name=f"Bot-{i+1}")
t.start()
threads.append(t)
print(f"{Fore.CYAN}Info:{Style.RESET_ALL} Bot started with proxy {proxies[i]} (Thread: {t.name})")
time.sleep(1)
else:
for i in range(bot_count):
t = threading.Thread(target=lambda: drivers.append(launch_browser(username=username)), name=f"Bot-{i+1}")
t.start()
threads.append(t)
print(f"{Fore.CYAN}Info:{Style.RESET_ALL} Bot started (Thread: {t.name})")
time.sleep(1)
threads = []
for i in range(count):
bot_name = f"{base_name}_{i+1}"
t = threading.Thread(target=launch_and_ready, args=(bot_name,))
t.start()
threads.append(t)
time.sleep(1.5) # Prevent CPU spikes

for t in threads:
t.join()

game_id = int(input(f"{Fore.CYAN}Input:{Style.RESET_ALL} Which game ID to join (7 = Contest): "))

for driver in drivers:
select_game(driver, game_id)

if input(f"{Fore.CYAN}Input:{Style.RESET_ALL} Type 'quit' to close browsers: ").strip().lower() == 'quit':
print(f"{Fore.GREEN}Info:{Style.RESET_ALL} Closing all browsers.")
cleanup()
print(f"\n{Fore.MAGENTA}All bots are attempting to join. Check the browser windows!{Style.RESET_ALL}")
input("Press Enter to close all browsers...")
cleanup()

if __name__ == "__main__":
try:
main()
except Exception as e:
print(f"{Fore.RED}Error:{Style.RESET_ALL} Unexpected error: {e}")
print(f"{Fore.YELLOW}Cleanup:{Style.RESET_ALL} Attempting to close all browsers...")
finally:
except KeyboardInterrupt:
cleanup()
Empty file added test.py
Empty file.