Skip to content

Schnurzel700/BTD6bot

 
 

Repository files navigation

BTD6bot

Overview of different gui windows (help window excluded)

BTD6bot is a program for automating Bloons Tower Defense 6 game.
It includes a simple graphical user interface: not visually impressive, but easy to use and offers a lot of functionality.

Supports only single player game modes accessed under the main menu "Play" button.
Support for multiplayer/competitive modes such as races, bosses, contested territory, boss rush, etc. will not be added.

Bot is quite complex and has been tested thoroughly, but you may still encounter bugs.

Btd6 includes elements of randomness, which cannot be removed entirely. On top of this bot's text detection times can vary ever so slightly which alters upgrade and ability timings etc. If you're planning to use bot to obtain Chimps black medals on harder advanced/expert maps, it could take several attempts before getting a successful run.

-- Warning --
Be aware that automation/botting is against Ninja Kiwi's Terms of Service and imposes the risk of flagging your account for cheating, or worst case, getting it banned.
I'm not certain how they could enforce this ruleset in a single player environment, though. If you're concerned, you can always run bot offline.
You have been warned.

-- Contributions --
If you'd like to contribute to project, for example add new game plans, see Contributions section.


[Update status]

  • Latest version of bot is 1.0.0 which matches BTD6's Update 54.

    => Release notes can be found here

    • For now, bot is planned to be updated after each major game update. These updates are marked as 1.X.0
    • Sometimes bug fixes, small changes, new plans etc. are added between updates. These patches are marked as 1.X.Y
  • All available game plans are listed here

    => Plans were previously updated in 1.0.0. Next update cycle is scheduled for 1.2.0.

    • Main goal is to keep all Chimps plans updated and add any missing ones. This process is repeated every 2-3 updates. Other plans could stay untested for extended periods of time, but then again, are also less affected by tower balancing/price changes.

[Supported display resolutions]

  • Resolutions with 16:9 aspect ratio are recommended as bot can easily scale mouse/text locations between similar interfaces.
  • With ultrawide resolutions, game seems to restrict in-game area into a 16:9 box and extend unused space with border texture. With some adjustments bot should work just fine (but this has not been tested).
  • For an arbitrary aspect ratio, game is likely to add or remove vertical/horizontal border textures and change button/text locations during gameplay. Bot has two solutions for this:
    1. use windowed mode and try to force the game into 16:9 resolution using launch arguments
      • useful if your OS doesn't support 16:9 natively
    2. game border shifting + manually re-recording all location (very tedious)
      • for borders: check manually the pixel widths/heights of border textures, then add this offset using 'in-game resolution shift' setting.
      • for locations: record all static coordinate locations on your current resolution and replace existing custom values: this requires a lot of work

[OS support]

Because of limited access to other operating systems than Windows, it's very difficult to ensure bot works on all of them. Currently:

  • Windows (10 or higher) is fully supported and thus recommended.

  • Linux: tested partially on

    • Linux Mint 22.3 (Xfce)
    • Debian 13.4 (GNOME)
    • Arch Linux (Hyprland/Wayland) - screenshot support via grim

    Not all features have been tested, but since main functionalities (gui, kb+mouse automation, ocr) do work, bot should operate just fine.

    Linux requires some additional dependencies to make Python, ocr, kb+mouse etc. function properly. These are documented and explained during installation process

    Wayland support: On Wayland-based compositors (e.g., Hyprland, GNOME on Wayland), bot uses grim for screenshots. Install it via your package manager:

    • Arch: sudo pacman -S grim
    • Debian/Ubuntu: sudo apt install grim
  • MacOS => Not supported, but could still work

    Bot functionality remains largely untested without access to modern native Mac system i.e. owning a Mac PC. Thus the responsibility of testing is left to user.

    • some code-level testing has been done using VirtualBox on much older versions (Catalina, Big Sur):
      • custom gui-only hotkeys are disabled for Mac systems. Reason is Python libraries used for gui and hotkeys (tkinter & pynput respectively) interfere with each other due to them running on same main thread. Thus hotkeys must be typed manually. Also bot can be still halted without hotkeys by quickly dragging mouse cursor to upper-left corner.
      • mac uses 16:10 aspect ratio as a baseline and lacks the support for recommended 16:9 resolutions. Again, this can probably be fixed by using the tricks explained above in resolution section.
      • if using running the bot inside gui doesn't work, you can use the no-gui version of bot. You can still use gui to update settings, hotkeys and plan queue, then close gui and switch to no-gui version.

The only "OS-independent solution" would be a dual boot setup: install a separate Windows version/widely supported Linux distribution, then run btd6 + bot in this environment.

  • Don't try to use virtual machine. These cannot properly utilize GPU which makes your game run on extremely low fps.

[Future updates]

Will mostly depend on what features/changes BTD6 does. For bot this usually means:

  • add support for new towers/heroes
  • add Chimps plans for new maps

Since bot has reached version 1.0.0, it's unlikely any major features gets added.
Some possible ones with no specific ETA:

  • project code/structure changes:

    • update plans directory structure by adding subdirectories for each map
    • use a proper plan file format like yaml/toml/json instead of python files. Would require a major rework of the codebase, but also make writing plans much easier.
    • go over entire codebase and see if there's anything that absolutely needs to be updated/reworked
    • add integration test suite: unit testing the bot is difficult due to extensive ocr usage. To do this: either build a simple simulation environment, or prepare and use a sequence of test images
  • add support for farming in-game achievements in some form

Table of contents

Features

  • [Tested on 1920x1080 resolution + fullscreen, with around 90-144 constant fps; normally 144, but with more stuff on screen it could go all the way down to ~90]
    All maps on CHIMPS difficulty are supported. As bot is required to finish any plan in one go, this also means CHIMPS includes black medal/border.

  • Graphical user interface (GUI) made with Python's build-in Tkinter library. Very simple when it comes to visuals, but easy to use. Here are some of the properties:

    • set bot hotkeys
    • change display settings to match your in-game settings like custom resolution or windowed mode
    • run a single plan or create a customized queue of multiple plans. Plans can be searched and sorted with custom regex
    • farm collection event rewards. Bot selects only Expert maps with bonus rewards and runs them on Easy-Standard
    • see info for currently selected plan if available
    • auto-record round times and check the generated time graph of most recent record with "Show plot" button
    • see all the printed text that bot outputs during runtime

    For gui visuals and in-depth look on all features, see GUI windows section.

    Bot can also be run without gui by using -no-gui command line argument. This version shares some of its settings with gui version so ideally you change settings in gui, close it and run no-gui version after. Otherwise you need to edit gui_vars.json file directly.

  • Support for various resolutions settings:

    • 16:9 aspect ratio + fullscreen (recommended)

    • 16:9 aspect ratio + windowed mode (also recommended, requires a bit more setup).

      • window location is defined by its top-left coordinate. On Windows, bot can auto-detect this position. Otherwise user can simply use provided tools to pinpoint this value
      • Btd6 can also be run with -popupwindow launch argument to remove title bar on top of game window. This sets game window in the middle of screen by default, but there's a simple way to setup window location beforehand. More importantly, you can also use -screen-width and -screen-height arguments to force 16:9 resolution.

      => works fine, but decreasing window size too much could reduce bot's text reading accuracy

    • aspect ratio greater than 16:9 + fullscreen, but game events must occur in an area with 16:9 aspect ratio. For example, with 3440x1440, the actual game screen area is 2560x1440 which has exactly 16:9 ratio

      => should work, but similarly to windowed mode, could face some accuracy issues

    • other non-16:9 resolutions are technically possible, but require a lot of setup

  • Support for creating custom plan files. Plans include all the commands bot performs on each round until a map is finished.

    • Note that commands are Python code so plan files are stored in .py format. In particular, monkeys and heroes are custom class objects because this makes implementing new features for them much easier. It also simplifies writing more complex plans. Commands are not very hard to write, but using them effortlessly can take time.
    • A plan template is provided which can then be copied and modified. Furthermore, the command_tracker tool is specifically designed for setting up new plans although it's somewhat convoluted. An alternative is to use simpler show_coordinates tool and write commands manually.

    See Creating a new plan section for more info.

  • Extensive bot tools with built-in gui support, which can also operate independently; there's gui-free command line version of bot. Uses optical character reading (ocr) and kb+mouse to update bot state.
    While bot code is thoroughly documented, Updating the bot provides baseline for adding new content should this project no longer receive updates.

Installation

First you need to install Python
Supported versions: 3.12, 3.13, 3.14

  • Windows: download the installer and follow instructions
  • Linux: easier to download via command terminal with sudo apt install python3 or similar

To install bot you have two options:

  1. automatic installation using a script file. Running the script will

    • download a zip file of main branch files of this project. Zip file is placed into same directory where you ran the script,
    • extract bot project directory from the zip. This is again placed into same location where you ran the script. Then delete this zip file,
    • setup script executables to run bot + include dev tools scripts
    • setup a Python venv virtual environment for bot project
    • install external packages from requirements.txt to this virtual environment

    After installation you go to bot install directory and run run.bat/run.sh file to start bot.

    See Use batch/shell script file for details

  2. manual installation by downloading source files and installing dependencies yourself. Still very easy to do and you might prefer this in case you

    • want to customize your installation,
    • failed to install bot with auto-install script, or
    • don't trust/want to use install script files

    See Manual install for details

Option 1: Use batch/shell script file

Windows user -> you might need to do this before running the script if you have not used Python virtual environments before

Linux user -> you should check this to avoid issues during and after installation process

  1. Navigate to Releases page

  2. Select newest available version

  3. Download one of the two script files depending on your operating system

    • install.bat for Windows users
    • install.sh for others

    You shouldn't download the auto-generated Source code.zip (or .tar.gz) file. This is for manual installation only.

  4. Replace .bat with .sh and everything here works the same:
    When you run the install script, it will download the current github main branch as a zip file and automatically unzip the contents under a directory BTD6bot-main in script location. So for example

    • You move install script into custom location "c:/your/path/install.bat"
    • You run install.bat -> bot files are generated under "c:/your/path/BTD6bot-main"

    After this, it will copy bot scripts for from "c:/your/path/BTD6bot-main/_install" and move them to other directories. These include

    • run.bat and run-nogui.bat into "c:/your/path/BTD6bot-main" so you can run the bot in default gui mode or in non-gui mode.
    • tools scripts: command_tracker.bat, image_scaler.bat, move_mouse.bat and show_coordinates.bat into c:/your/path/BTD6bot-main/tools/{script_name}. Unless you want to create your own plan files or add own features to bot, you don't need to interact with these at all.

    Finally it will create a virtual environment under c:/your/path/BTD6bot-main/.venv and install external Python packages listed in requirements.txt to this environment. This way Python packages required for bot are isolated and won't cause issues if you happen to use other Python programs.

[Notes]

  • You can move and rename BTD6bot-main directory freely, just don't rename any files inside it unless you know what you're doing.
  • for more details such as step-by-step explanation of script code, check here

Option 2: Manual install

Linux user -> even if you're not using batch file install, check the Linux section of installation document. It explains important concepts to ensure bot operates as expected.

Download BTD6bot files. Main branch is selected by default and it's the recommended way to run bot:

  • main is the release branch. It has the most stable version of bot with minimal amount of bugs.
  • dev is the development branch. All upcoming features are added and tested here before they get merged into main. Expect this version to be less stable and include numerous bugs.
    $~$

For manual install, you have two options

[Method 1] go to Releases, click the latest version and download the Source code.zip. Unzip the directory to your desired location

[Method 2] Click the green [<> Code] button at the top of github page.

Then either

  • clone this repo to your local machine (can also do this from command terminal), or
  • click "Download ZIP" and extract the contents


After following either method 1 or 2, you should have project files ready.

Next: external dependencies. Install the following third party packages:

matplotlib==3.10.8; python_version >= "3.14"
matplotlib==3.10.1; python_version <= "3.13"
numpy==2.4.2; python_version >= "3.14"
numpy==2.2.3; python_version == "3.13"
numpy==1.26.4; python_version <= "3.12"
pillow==12.1.1; python_version >= "3.14"
pillow==11.1.0; python_version <= "3.13"
easyocr==1.7.2
markdown==3.8
pyautogui==0.9.54
pynput==1.7.8
pyperclip==1.9.0
pywin32==311; sys_platform == "win32"
mss==10.1.0
tkinterweb==4.3.1
tkinterweb-tkhtml==1.0

To install dependencies easily: open command terminal, change your current directory to <your path>/btd6bot where you installed BTD6bot, then type

pip install -r requirements.txt

This might take a while so just wait patiently. When the process is done, you can move onto First-time setup.

[Note 1] easyocr library defaults to cpu for text detection/reading. Cpu works just fine, but if you'd prefer it to use gpu instead, check out PyTorch local install guide and select appropriate CUDA version.

[Note 2] Exact versions of packages as listed above might not be required, but are always recommended. For pynput and tkinterweb-tkhtml however they are mandatory:

  • pynput 1.7.8 throws a critical error if any gui hotkey is used
  • tkinterweb-tkhtml 2.0 raises ImportError if tkinterweb library is imported

First-time setup

Main window default view

To run BTD6bot, try one of the following:

  • If you used install script, open your BTD6bot folder then run the run.bat or run.sh file
  • Otherwise open command terminal, set current directory to <your path>/btd6bot then type py btd6bot
    • if you'd like to run non-gui version instead, use py btd6bot -nogui

If you managed to run BTD6bot then a window similar to above should have opened. There's plenty of stuff in here, but for now focus is on getting the bot to work properly in your system.
Following steps must be done in order to make bot work properly for each user:

1. Update bot hotkeys
2. Settings: update resolution and enable ocr auto-adjust
3. Run the ocr adjusting process

Below is a quick tutorial of first-time setup. After it begins the full tutorial, which is detailed and quite long.

[Quick vs Full tutorial]
If quick summary seems difficult to understand, or you think you got something wrong, just switch into full tutorial:
It's highly recommended you read through full tutorial at least once.

Getting the bot to run properly is the hard part (which is not that hard).
You're free to experiment with all the gui settings afterwards, and if needed, can repeat first-time setup steps should something break irrevocably.

Quick tutorial

1920x1080 monitor is used below; your values may look different
1600x900 is used as custom resolution example

  1. Set hotkeys in Set hotkeys window; gui hotkeys are not mandatory, but very much recommended. After you're done, close hotkeys window.

  2. Open Settings window and set resolution.

    Select a resolution with aspect ratio of 16:9 AND prefer fullscreen.

    • If you use fullscreen, don't enable custom resolution, or use windowed mode. Just leave it untoggled.

    • If you use custom resolution, set width & height values, then update values.

      • Toggle windowed mode on if you wish to use it. It's recommended to always use fullscreen, but windowed should also work - just requires a bit more setup.

      For windowed mode you should head to GUI settings page as it's a little more complicated to explain here.

    • Aspect ratio greater than 16:9 might be compatible, if you use fullscreen in-game, but set bot to use custom resolution and windowed mode in order to limit the area the bot sees; check Ultrawide resolutions for more info.

  3. Enable ocr auto-adjusting, make sure it has correct res and win values:

  • Res is your current resolution, win stands for fullscreen (win=0) or windowed (win=1).

  • Your winpos argument tells game window position if win=1; if you use fullscreen its value doesn't matter.

  • Shift value shift is most likely also useless unless you intent to try running bot with non-16:9 resolutions.

  • Finally, monkeys=all and delta=4 values should be automatically set. Easiest way to do setup all of this is to just press Reset args then Set args button to save args.

    Your argument prompt should look similar to this:

    Why adjusting is needed: monkey upgrading process is based on reading upgrade path names from screen and matching these to static values. Different resolutions change the reading accuracy so bot will automatically adjust each upgrade path individually to minimize matching errors.

    Know that any time you change resolution or windowed mode, it's recommended to re-enable auto-adjust setting and run this process again!.
     

    Now close the settings window. In main window, press Initialize bot, wait a bit for initialization (this might also happen pretty much instantly unless you're using an older cpu), then press Open bot window to open monitoring window.

    Have your Btd6 game opened on main monitor (or if windowed mode then possibly on any secondary monitor), placed in main/home menu screen with Play button visible. Now run the bot and let it finish auto-adjusting. This process can take a while.
    After adjusting process is finished, bot should be able to detect in-game upgrade texts properly based on your current resolution settings.

    Finally, test if bot works by running a simple plan:

    Close current monitoring window instance, then select either dark_castleEasyStandard or monkey_meadowEasyStandard.

    Then press Open bot window again to open fresh monitoring window and press Run. Don't use keyboard or mouse while bot is running.
    If bot can finish a plan and returns to main menu with "Plan completed" message, everything should be ok!


Full tutorial

Update bot hotkeys

Open a game instance of Bloons TD 6. Click the gear symbol and open hotkeys menu.

Now update your game hotkeys for bot. Press "Set hotkeys" button in gui. Following window opens:

Hotkey window

Under "Hotkeys" label, there are two windows: top one is for game hotkeys, bottom for gui hotkeys. Game hotkeys you simply copy from btd6, gui hotkeys you select freely.

You should quickly read the "Instructions" but here's the important parts:

  • Not stated, but should be obvious: Do not use same hotkey for two different actions
  • You can scroll hotkey panel down to find more hotkeys
  • supported keys:
    • letters a-z, digits 0-9, other symbols like +, -, *, § etc.
    • numpad keys 0-9; these show up as <96> to <105>
    • modifier keys; these are displayed as Key.keyname e.g. Key.ctrl
  • Some keys like § might get displayed weirdly but should still work
  • Custom gui hotkeys:
    • "pause" queues up a pause flag. When bot hits it, it will press esc to pause game and also pauses bot. To unpause, press this button again.
      • Do not close the esc menu manually or bot and game will likely get desynced!
      • Pausing only works in maps and does nothing when bot navigates menu screens
    • "start-stop" starts/stops the current bot loop. Stop will also reset the loop which means you need to start bot from main menu again.
    • "exit" stops BTD6bot entirely: it forcefully terminates current bot loop and closes all existing gui windows. Set this on a keybind that you don't press accidentally.

To update a hotkey

  • click on any line so it becomes highlighted
  • press "Set hotkey" button at the bottom
  • "Set hotkey" button is now greyed out: press any supported keyboard key to update value
  • you should now see the right side of = get updated

After you've updated all the keys, close the hotkey window.

Settings: update resolution and enable ocr auto-adjust

Next, open settings window by pressing "Settings" button.

Settings window

For now, only 3 settings are needed:

  • resolution (native or custom resolution)
  • windowed mode
  • auto-adjust ocr upgrade data the next time a plan is run

First the important part: the base layout of Bloons is made for resolutions with aspect ratio of 16:9 or very close to it. For this reason, bot is also programmed around this requirement.
Resolutions clearly differing from this are unlikely to work. The reason is that game will extend existing borders or even change the general ui layout (like text locations) for some aspect ratios.

Now, despite this, it might be possible to run different resolutions, for example ultrawide resolutions, as long as they don't change the relative positions of ui.
For such cases, you will probably need to do some tricks with windowed mode enabled, even if you plan to play in fullscreen. Check Ultrawide resolutions for more detailed explanation.

Assuming you've decided which resolution to use, you have two choices:

  • fullscreen with native screen resolution: if you toggle the "Enable custom resolution" option off, you should see your current resolution next to "Current resolution" text.

    For example, if your monitor is 1920x1080, you see following

  • custom resolution: type width and height in their respective entry boxes, then click the "Update resolution" button.
    Custom value is stored in a file and will be loaded back if you disable and re-enable this setting.

    Example: if you have 1920x1080 as native res and set a custom res 1600x900, then toggling setting on and off would display following resolutions:

    With custom resolutions, you can enable windowed mode.

    Setting up windowed mode requires a bit more explanation so go check GUI settings section.

    Using windowed mode can decrease the text quality for ocr, though. If you use significantly smaller resolution with windowed mode, bot could have issues with verifying text inputs.
    If windowed causes issues, just use fullscreen instead.

Lastly, enable the "Auto-adjust ocr upgrade data the next time a plan is run" option. For 1920x1080 with fullscreen enabled, it looks like this:

It should include following parts, each separated by space:

  • res="width"x"height"; where "width", "height" are based on your own resolution,
  • win=0 for fullscreen, win=1 for windowed,
  • winpos=VAL where VAL can be centered, auto (Windows OS only) or X x Y where X, Y are game window top-left coordinates. If you use fullscreen (win=1), this value doesn't matter,
  • shift=0x0 or some other custom value if you attempt to use a non-16:9 resolution,
  • monkeys=all,
  • delta=4

You can press "Reset args" button once, if res and win values are not immediately updated.

Then just press "Set args" and you're done! You may now close the settings window.

Run the ocr adjusting process

For last part, you need to enter the monitoring window. Click the "Initialize bot" button, located at bottom right of main window:

Following load message appears (or might just quickly flash if your computer is fast enough)

Program needs to load the ocr model into your temporary memory (RAM) each time you initialize bot and is therefore only required once per runtime loop. If you close the entire program and reopen it, the model must be loaded again.
First time only: the up-to-date versions of both text detection and recognition models are downloaded automatically by easyocr. This process is only for first-time setups and will not be required again.

After the message disappears, model has been loaded and initialize button should now display "Open bot window" instead.

Click the button to open monitoring window.

Monitoring window

Monitoring window handles the running of bot and importantly, includes the big text window. All text prints get redirected into this window during bot runtime so you can have it on another monitor/same one monitor if on windowed mode in case you'd like to follow what bot is doing.

Before we begin the adjusting, it would be a good time to explain why it's needed in first place. I would recommend to read it through once, but if you don't care, skip the following wall of text.


[How does the upgrading system work]

Most ocr strings the bot will see are static i.e. have always same text value, and are quite easy to detect. They are used updating bot state and allowing it to make decision/execute commands. For certain commands, however, more complicated system are required to verify the input.

The most complicated of these is the monkey upgrade system. In order to make upgrading to work properly, bot needs to wait until upgrading becomes possible. The easy way to program this would be just say "when command is run, upgrade monkey, don't check if it was successful". But then user would need to time the upgrading exactly and this becomes obviously annoying over time.

So better but more complicated way to implement this is to allow user to queue upgrade checks. Bot will just wait until the upgrade flag is hit, then upgrade. But even then, there's a chance bot makes a mistake and upgrades too early or might not upgrade at all. For this reason, upgrading process must

  • queue upgrades
  • perform upgrading process when asked to
  • verify the upgrade process was successful

If it fails, it can either throw an error or keep trying again. The latter is how this bot works:

  • takes upgrade command

  • attempts to upgrade bot simply by pressing the right upgrade path hotkey

  • reads the current upgrade name, matches it with actual upgrade name, then
    compares the difference of these strings and outputs a delta parameter.

    • if delta is over the threshold, upgrade was successful
    • if delta was below the threshold, run the cycle again until above is true

This system is effective, but faces one problem: it uses same delta for ALL UPGRADES! Some upgrades might match easily, others being more difficult. And not only this, if two consecutive upgrade paths are similarly named, like "sharp shots" and "razor sharp shots", they could be confused as same. A single delta value cannot universally work with all previous cases. To solve this problem, current system uses individual deltas for each monkey and its upgrade paths.

Process is now as follows: upgrade checks monkey name and desired upgrade path, say dart 5-x-x. It then gets the actual string value for this path, "ultra juggernaut" and corresponding delta, lets say 0.85. If the upgrade input text is "ulta jugernaut", bot checks the following

  • actual string has 16 letters (spaces includes)

  • input string has 14/16 similar letters in similar order (*)

    (*) Matching system uses Python's built-in library, I don't know its exact implementation. But it does something similar to this.

  • 14/16 = 0.875 > 0.85, upgrade passes

  • however, exact delta value is avoided because some reading error could
    change output a tiny bit and then value could become 0.84 < 0.85 = no match

  • to give room for some error, a delta value is subtracted to lower this exact value. From testing, subtracting 0.04 from all deltas keeps good accuracy for the most part. In settings, this value is written as delta=4: it lowers all deltas by 4 units, where unit is 0.01. Valid deltas are 0-9 (which translate to values 0-0.09)

Above process is then repeated for all monkeys and all upgrade paths. In very loose terms, this 'trains' the bot to detect valid upgrade thresholds. Then, when you run any plan file, it should have rarely issues with upgrading and mixing inputs, thus working as intended.

Another thing you might be thinking of: Why not just use the cash value instead of upgrade names? Bot could just read cash value, wait until cash is there, then upgrade a monkey. Well, this would actually be just fine to do, but for this project:

  • cash values proved to be often inaccurate, especially on maps where background had other elements like snow. With upgrade texts, background is always the same.
  • upgrade costs would need to be updated in a separate file after each update. This is not really a big deal, but adds one extra layer of active maintenance.
  • Upgrading would need to performs additional checks for discounted prices e.g. monkey in range of 0-0-1+ village. This issue can be completely ignored now.

-- End of explanation --

After "Run" button is pressed and menu play button is detected, bot sets a countdown from 5 to 0, then begins the auto-adjusting process

Now to complete the final step you need to have your BTD6 game instance opened, placed at the main menu screen. Then, press the "Run" button or use "start-stop" hotkey you set previously.

Text window gets updated: the text "Ocr adjust mode enabled" pops up and signals that bot will perform the adjusting process. Bot is now active and is searching for the menu "Play" button text. After it finds it, ocr adjusting may begin.

During adjusting, do not use keyboard or mouse! Just wait until it's done. Bot should be able to return to menu on its own, but if there's an error and it gets stuck for more than 30 seconds with visibly doing nothing, do the following:

  • close current monitoring window and reopen it: window should still say current plan is spa pits, easy with Sandbox mode enabled
  • place your Btd6 game screen back to main menu screen, then retry the adjusting by pressing "Run" button

What is delta adjusting:

  1. bot automatically navigates to "Spa pits" map and enters it in sandbox mode
  2. goes over all the upgrades of listed monkeys, read their upgrade texts, check how closely they match to actual texts and save the obtained delta value for that upgrade string. Because monkeys=all, it checks all monkeys.
    • in the image above it says "beast" which checks only beast handlers, but you want to check all monkeys
  3. after it checks all listed monkeys once, it will check them again! This time it places them on opposite side of map. Why? In case you've never noticed, depending on which side of middle section you place a monkey (left or right), the monkey panel opens on the opposite side of screen. Different sides can, based on testing, produce slightly different inputs so bot will analyze both sides and save all the deltas.
  4. After both sides are checked, bot compares deltas of left and right side, selects the smaller value and save it as final delta for each upgrade string.
  5. Finally, all delta values are adjusted with equal amount. Default value is delta=4: this adjust them by 4 units. An unit is 0.01 so with 4, bot subtracts 0.04 from all values. This process is done to allow room for error. If delta=0, exact values are used, but then even a slightest error would break the ocr process, and eventually, the bot.
  6. Process is now done and your upgrades_current.json file inside btd6bot/Files folder has been updated. Bot will also automatically disable the auto-adjust option from setting so if you need to do this process again in the future, just open setting and enable it again with appropriate arguments.
Adjusting process complete. Current monitoring window must be closed in order to continue.

And if everything worked, you should now have updated all delta values for your current resolution settings. This means your bot is ready to be tested with an actual plan.

To run your first plan, it's recommended to pick something simple. Close the monitoring window and select either monkey meadow, easy-standard or dark castle, easy-standard in main window:

or

Make sure you have the required hero, all monkeys and their upgrade paths unlocked. For upgrade paths:

  • they follow the normal order of top-mid-bot e.g. sniper 2-0-4 uses 2. top path and 4. bottom path upgrades
  • they state highest crosspaths required. Therefore you sometimes see paths such as 2-5-5 sniper listed which simply means plan requires 2. top, 5. middle and 5. bottom paths. For example, such plan could use both 2-0-5 and 0-5-2 snipers, and maybe even include a few 0-3-2's.

Remember to scroll the info panel down to see all requirements!

Now reopen the monitoring window, have Btd6 menu screen opened, press run and just wait for bot to do its thing. If bot is able to finish a plan and returns to main menu automatically, everything should be working!

----- Full tutorial ends here -----

Resolutions with other than 16:9 aspect ratio

The advice explained here has not been tested completely. It should theoretically work, but I have only ran bot on a monitor with 1920x1080 native resolution.

Ultrawide resolutions

As stated under "Enable custom resolution", resolutions should have aspect ratio of 16:9. But it is possible to leave in-game resolution to your native fullscreen resolution, but still use custom resolution + windowed mode to reduce the visible screen area.

When you run Btd6bot with windowed mode, it uses the logic described in following image

Because windowed mode normally leaves empty space around, you could limit the readable area to the middle of screen. A good example would be 3440x1440 resolution: it adds extra borders during maps which is 440 pixels each side. This means the actual screen area is 3440-440*2=2560 times 1440 which has a nice aspect ratio of 16:9!
In fact, this should also work for menu screens because play and hero select button are in correct position relative to everything else. Only actually problematic case would be the map search button which falls outside the middle area, but there's a built-in checking system which should be able to locate this button specifically for ultrawide resolutions.
Example: So if you have a 3440x1440 monitor and wish to play on this resolution, go to gui settings:

  • enable custom resolution and set it as 2560x1440

  • enable windowed mode and keep top-left value as "centered"

    If value is not centered, simply type "centered" in one of the width/height fields and update

  • And of course remember to readjust ocr deltas for new resolution as always!

Here's a visual explanation on the situation (in main menu screen, but this applies to in-game ui as well):

In general, check the following:

  • run BTD6 and open any map on your desired resolution
  • find out the pixel resolution of actual game screen without the borders.
  • now check if the resulting resolution has close to identical aspect ratio 16:9. In above example, it was 2560/1440 = 16/9 which is exactly right.
  • (optional) if required, you could repeat this for y-resolution as well. But the problem should be extra width, not height, so this probably not needed. One quite forced, but still an example, would be 1280x800 - if you use this in-game, you notice how it adds a wider bar at top and bottom of the screen.
  • Then auto-adjust ocr values like usual and you should be good to go.

Any aspect ratio

(Images are not included, but might get added later)

If you don't use 16:9 aspect ratio resolution or can't get the above ultrawide setup to work, final option is to adjust coordinates for selected resolution. This will require a lot more work because you need to

  1. shift coordinates accordingly so bot's coordinate range fits inside border textures and any towers get placed in correct positions,
  2. change locations of clickable buttons and ocr text box locations so that bot can properly execute all its commands and validity checks.

Full explanation:
Game adds horizontal or vertical borders depending of current aspect ratio and extends them based on resolution. As shifting feature of bot is based on 16:9 aspect ratio, such as 1920x1080 resolution, 0 height means no vertical border and 0 width means some horizontal border width which gets added on each side of screen

  • as 16:9 resolution have no borders at the top/bottom of screen, it already has the minimal border height of 0. Thus, height can only get values >= 0 because other resolution can only possibly add more border.

  • 16:9 however includes a small border on both left and right side. It's length? Depends on user's monitor base resolution and current game resolution so it cannot be determined automatically. Thus width can get both negative and positive values because on certain aspect ratios, border is smaller/is removed altogether OR is wider than base border. To measure border pixel width/height, use btd6bot/tools/show_coordinates tool or something similar.

Unfortunately shifting can only adjust non-static coordinates (monkey/hero locations, ability targets etc.). Static locations like text and buttons do change between aspect ratios and therefore must be updated manually by editing the btd6bot/Files/custom_locations.json file.

For 1.

  • use btd6bot/tools/show_coordinates tool and measure the width or height of borders in pixels
  • use the Enable in-game resolution shift setting and set a custom value. With height (top+bottom borders) you simply add the height if necessary. With width, you have to just test this value because 16:9 resolution has a base border length so thinner/wider border must take this into account.

For 2.

  • open btd6bot/Files/custom_locations.json. You can also open btd6bot/bot/locations.py to check the info docs and see what each value represents. Only in-game locations should require changes: these are the following dictionaries
    • "CLICK" -> "ingame", "hero_left_menu" and "hero_right_menu"
    • "TEXT" -> "ingame"
  • again, use the show_coordinates tool. Save coordinates and change corresponding 2-tuple or 4-tuple values.

Now whenever you have the in-game resolution shift enabled, bot uses custom_locations.json coordinates instead. To use default locations.py values, simply disable shifting.

GUI windows

This section goes over all the gui windows and explains each of them in detail.

  • Each window has fixed size and cannot be adjusted (dynamic window scaling might be implemented at some point, but no promises)
  • Gui interacts with Files folder. Don't change data values of these files manually unless you know what you're doing
    • only exception is Files/map images in case you'd like to replace ascii texts with map images. Check sections for Main or Queue for more info.
  • Images are screenshots from Windows environment. Different operating systems will always change the look, but general layout should remain the same.

Main

Main window, with ocr already initialized. Currently selected plan is bloody_puddlesHardChimps, with collection event and replay modes enabled.
  • Responsible for running the program main loop: if closed, entire program closes.

  • Includes buttons for other windows (Help, Settings, Hotkeys, Queue, Monitoring)

  • Includes drop-down lists of all maps and their respective available strategies. Displays info text for current plan i.e. selected map + strategy combination. Info is stored in each plan file and can be freely customized.

    • both drop-down lists support quick search: when opened simply press any character and if map/strat begins with that character, it gets selected. Repeating same character keeps looping over all matching entries.
  • Has toggle buttons for

    • collection event mode: this will check if pop-up window appears after a plan is finished and collects the rewards
    • farm mode: can only be toggled on with collection event mode. Bot will farm expert maps on Easy, Standard and always selects the current map with bonus rewards. This loop continues until user stops it manually (or if some fatal error happens which bot is unable to handle). Farming does not require any monkey knowledge and only hero used is Sauda.
    • queue mode: loads all listed plans from queue mode maplist and plays them one after another
    • replay mode: replays current plan or queue of plans until bot is manually stopped. If used with queue of plans, plays all plans once, then start over again from first one.

    All of these modes work with one another so you can have all disabled/enabled, or mix them.

  • "Show plot" button opens a new process window which displays saved time and round data for currently selected plan. Data is updated after each successful completion and also includes date of completion in YYYY/MM/DD format.

  • (Optional) You can add map images to replace the ascii art.

    To do this, have map images saved in "Files/map images" folder and make sure they follow correct format:

    1. only letters and spaces allowed

    2. only lowercase letters, special characters are allowed (like # in #ouch, ' in adora's temple)

    3. image resolution is 320x195

      • you can use tools/image_scaler for this
    4. file format is png

    For example, if you wanted monkey meadow, x factor and #ouch map images, files should be named

    • monkey meadow.png

    • x factor.png

    • #ouch.png

    Map images can be downloaded from https://www.bloonswiki.com/List_of_maps_in_BTD6

Help

Help window, expanded to fullscreen. It displays the same README contents, however none of the links are in working condition
  • Help window displays the document you're currenly reading (either in web browser or inside gui help window). It's meant for offline mode in case you don't have access to web version. However, it should have exact same contents as web version so you can use it as replacement, too.

  • It has dark mode always enabled.

  • Comes with one major issue: none of the links work. Reference links simply point nowhere in document, web links display some random mess so don't try to use them either.

Also something worth to mention: the offline readme is actually an html document translated from the README markdown file. Annoyingly, the Python library used for this conversion requires absolutely file paths in order to display all images. This means that resulting README.html file has to save full file paths of your BTD6bot install folder.

  • To avoid storing paths in this file for extended periods, each time a Help window is closed or program is rebooted, BTD6bot will automatically delete this README.html file.
  • Of course, a new one needs to be also generated each time you open a new Help window. But again, after closing Help or reopening the Main window, this file gets deleted again!

Queue

Queue window with infernal_EasyStandard and flooded_valleyHardChimps plans placed in queue. When a plan is selected, its info text gets displayed.
  • Shows all existing plans and currently selected plan queue. When a plan is selected, its info panel is also displayed.

    • if a plan is added to current queue, it no longer appears on All plans list until it gets removed. This makes it easier to see which plans are already added. Info texts are exactly the same you see on main window page.
  • You can use the "Add" and "Remove" buttons to add new/remove existing plan in queue.

    • There's also "Remove all" button which removes all queued plans
  • Currently selected plans can be moved up/down in order by pressing arrows right of current queue panel.

  • Has a search box for all available plans. This makes it easier to find specific plans by using keywords such as map name, difficulty or game mode.

    • searching has 3 separate ways to match plans:
    1. exact match: plan name as its written e.g. monkey_meadowEasyStandard. Not case sensitive so monkey_meadoweasystandard also works

    2. map name with spaces: same as above, but underscores in map names are spaces e.g. monkey meadowEasyStandard

    3. plan name words separated: non-case sensitive, underscores become spaces and difficulty & game mode are also separated with spaces e.g. monkey meadow easy standard

      Search will always keep matching until it finds a string or plan name is searched entirely. This means you also just write "easy", "easy standard", "mediumChimps", "Hardstandard" etc. and it will find all easy difficulty plans, easy standard plans, medium chimps plans and so forth. But searching "standard easy" cannot match because it would need to find word "standard" before "easy".

    • a special search syntax *v{OPERATOR}{VERSION} {TEXT} can be used for searching plans with specific game versions. This is mostly for testing/updating purposes as it makes easier to search older plans that should be tested and possibly updated for current version.

      • Operator gets value <, > or = to include plans with version less than, greater than or equal to VERSION value.
      • VERSION is game version integer value
      • TEXT is any search text and follows same matching ruleset as described above. Notice the space between VERSION and TEXT: if no space, no matching is done but if space is included, TEXT is automatically treated as empty string which display all plans fitting the given version restriction.

      Examples:

      • *v<52 (has empty space after version) -> displays all plans with version less than 52 (so 51 and below)
      • *v>50 dark -> all plans with version greater than 50 and starting with "dark". So for example it could find all plans of dark castle, dark dungeons etc. with versions 51 and onward
      • *v=51 easy primary -> finds all easy difficulty on primary mode with version 51
      • if plan has no version data saved yet, it can be searched with *v=-.
  • When queue mode is toggled on in main window, bot will use this plan queue instead of currently selected plan in main window.

  • Hotkeys

    • Shift + a -> Add selected plan to current queue
    • Shift + r -> Remove selected plan from current queue
    • Shift + u -> Move selected plan in queue up
    • Shift + d -> Move selected plan in queue down
    • character key -> if any plan in current queue list or available plans list if selected, search next plan starting with this letter in that list
      • generally Shift + CHAR combo is reserved for other hotkeys, but some special symbols "#" such as (Shift+3) also allowed

Hotkeys

Hotkey window.
  • Used for updating bot hotkeys.

  • Includes instructions window. Not very long so you should read through it once.

  • Hotkey panel is divided into two parts:

    • upper part is for in-game hotkeys, which must match with Btd6 in-game hotkeys
    • lower part is for gui hotkeys. These work either always (exit) or when a monitoring window exist (pause, start-stop)
  • To update a key:

    1. simply press any line on hotkeys panel,
    2. press "Set hotkey" button, then press any supported keyboard key
    3. value for that line should now display the updated value on the right of = sign.

    Note that some symbols might show up weirdly, but the hotkey should still work.

  • hotkeys are reloaded each time you open a new monitoring window. So remember to close current one if you updated any of them.

Settings

Settings window
  • Includes basic and advanced settings. Advanced settings are mostly for internal testing, except the auto-adjust option, which was already introduced when setting up the bot first time.

Explanations
(Basic)

  • Enable custom resolution: Change resolution the bot uses to determine relative mouse clicking/ocr text locations. Must match with used in-game resolution which should have 16:9 aspect ratio.

  • Windowed mode: Whether Btd6 is run in windowed mode.

    You can run Btd6 normally or with -popupwindow launch option.

    • normally game window includes the application top bar which says 'BloonsTD6'. Because bot is inertly build for fullscreen resolutions, it's assumed this bar doesn't exists.

      To use windowed mode properly, you have to pinpoint the actual game window top-left coordinate:

      See the Set window top left coordinate part below for more info.

    • alternatively, Btd6 can be started with -popupwindow launch option. This makes game window unmovable from its initial centered position (but doesn't mean position cannot be changed), but does remove the application bar

      To setup -popupwindow: if you use Steam version: library -> bloons td 6 -> right-click -> properties, then set the following value

      You can also add optional -screen-width X and -screen-height Y args here to force custom resolution, e.g. -popupwindow -screen-width 1920 -screen-height 1080.

      To do this without game launcher: make a desktop shortcut of BloonsTD6.exe, right-click Properties and add -popupwindow (and any other args) at the end of target path e.g. "...\BloonsTD6\BloonsTD6.exe" -popupwindow.

      To move window outside the centered position, you have to:

      1. open Bloons TD 6 without -popupwindow enabled
      2. then set desired windowed resolution
      3. move game window to desired position
      4. close game and enable -popupwindow

      Any resizing will reset window position back to center (e.g. Windows -> Alt + Enter)

    [Note] Windowed mode can face issues with ocr accuracy. If resolution is considerably smaller compared to base one, text reading errors become more common.
    Therefore it's always recommended you use fullscreen or run windowed on high resolutions only if you start having frequent detection errors.

    For ultrawide resolutions: a special case of windowed mode is to enable support for ultrawide resolutions; check this for more info.

    Set window top left coordinate

    No matter if you chose to run game with or without -popupwindow, you do need to specify game window location for bot.

    There are 3 possible values for adjusting window location (= actual pixel positions) to bot coordinates:

    • centered => if user enters value "centered" to either width or height field.

      Bot assumes game window is then evenly centered: this can be easily achieved by setting game into fullscreen and back to windowed. On windows for example this can be done by pressing Alt+Enter twice.

      • this is default value on non-Windows OS, but also not very useful
    • auto (this is for Windows OS only!) => if user enters value "auto" OR empty value to either width or height field.

      Eenables automatic game window tracking and is the recommended way to use windowed mode for Windows users.

      • this is default value on Windows OS; for Mac/Linux there exists no simple way to implement universal auto-detection of window coordinates. On Windows, the wingui32 library makes this easy.
      • enabling this setting will also automatically update your resolution in real time so you don't necessarily need to input custom resolution value!
    • actual coordinate value => if user enters valid resolution values to both width and height fields

      The top-left pixel position of game window. For this user must manually find the top-left coordinate and enter its width and height into their respective fields, then update. Bot can then use this top-left location as baseline together with custom resolution and operate as expected. Note that one or both the x & y values can be also negative depending where the game screen is relative to your main monitor e.g. if you have two monitors side by side with right being main monitor then any coordinate on left monitor has a negative x value.

      To find coordinate value easily, you can use the btd6bot/tools/show_coordinates script tool.

      • remember to always update the top-left position after you move the BTD6 game window!

    As always, remember to re-adjust ocr upgrade values if you changed resolution by pressing "Reset args" then "Set args" and run the adjusting process again.

  • Game version: Current major game patch version. For example, if version is 48, 48.1, 48.2 etc. just use 48. This value is used to update plan info and verify the plan works on current version after bot successfully finishes it.

  • Retries: How many times the bot will retry current plan before moving on to next one. However, if bot finishes before reaching this limit, it behaves as usual: if a single plan, bot finished; if queue mode enabled, moves onto next plan. It's recommended to keep these value somewhere around 5 as some expert maps in particular have rng and can fail once or twice before getting over the problematic round(s).

(Advanced)

  • Enable in-game resolution shift: Shifts all non-static coordinates relative to middle coordinate by given amount of pixels. Width and height can be adjusted individually. Positive values shift towards mid point, negatives away from it.

    It's main use is to move coordinates out of border textures when user has a non-16:9 aspect ratio resolution. See this section of advanced resolutions guide.

  • Ocr time limit: How long will bot attempt to search for various text flags before it gives up and attempts to return to main menu. Typically, this should never occur so a high value of 300 seconds or more is recommended: this is especially important for apopalypse plans as in those you can have long periods of downtime where bot attempts to place/upgrade a monkey.

  • Ocr frequency: Pause interval between most ocr operations, in seconds. Naturally every operation has base cost which depends on cpu/gpu speed on top of which this value is then added. Raising this value will greatly decrease cpu/gpu load, but makes ocr slower. For normal use, keep this value around 0.01-0.1. For simple repeating processes such as farming xp/monkey money on dark castle easy/deflation, you could set this value to even high as 0.5-1 if you plan to leave bot running for extended periods of time and want to keep cpu/gpu usage low.

  • Upgrade checks: Amount of checks upgrade system performs before it presses upgrade any upgrade hotkeys again. This process then simply presses upgrade button -> performs N checks -> if upgrade successful, continue; otherwise keep going until counter hits N+1, then press button again and repeat. In most circumstances this setting matters little, but it will likely prevent the following "bug":
    Say you want to upgrade a dart monkey from 0-0-0 to 4-0-0 in one go. If game for some reason stutters even for a tenth of a second, ocr fails to read the upgraded text at the right moment. Then 0-0-0 becomes 1-0-0 in-game, but internally bot still sees 0-0-0. It then upgrades the monkey again, resulting into 2-0-0 but still bot sees 0-0-0. This of course keeps continuing until ocr time limit counter gets hit and bot will auto-quit current plan. Now if counter value N > 1, bot would initially perform upgrade 0-0-0 -> 1-0-0, then check this process N times before attempting to upgrade again. As it's unlikely such stutter happens multiple times in a row (and if it happens, increase the value N further), bot now confirms the upgrade on second try and updates the internal state to 1-0-0 as well.
    Default value is 3. Increasing value a bit shouldn't affect bot performance nor functionality whereas decreasing it is not recommended unless you're running bot on older computer.

  • Use gpu in ocr: Enables CUDA support if both operating system and gpu supports it AND you installed pytorch cuda-version during installation. This will likely increase the speed of all ocr functions. However bot can operate just fine with cpu, and MacOS doesn't even support CUDA so this setting is (or at least should be) disabled by default.
    To enable CUDA support, you must install a cuda-supported version of pytorch library.

  • Enable logging: Enabled text logging. Each time a new monitoring window is created, a new Logs.txt file is created in project root folder. All the text bot prints is then simply copied into this file which is useful for debugging/testing the bot.

  • Print ocr (delta | substring) text values in monitoring window: Enables detailed text printing for ocr processes which use delta matching | substring matching. For example, monkey placements and upgrades use delta matching whereas finding current round number uses substring matching.

  • Auto-adjust ocr upgrade data the next time a plan is run: This was already introduced under first-time setup. Updates all upgrade ocr values based on current resolution settings. As bot uses upgrade labels to determine whether is has successfully upgraded a monkey or has to keep on trying, these texts must be as precisely readable as possible. For upgrades, bot has three cases:

    1. not mixing and accepting similar strings like "sharp shots" & "razor sharp shots",
    2. not accept too weak a string
    3. accept strings that are good enough.

    To ensure these all work in harmony, bot uses three identifiers:

    1. monkey name with upgrade path e.g. dart x-2-x
    2. static string it matches to e.g. "very quick shots"
    3. a delta value of how much the output needs to match with static string. So 0.8 means 80% of static string's symbols must be found in ocr output string, in similar order. Now each upgrade path has individual delta value which should be high enough to ignore false strings, but still accept a string that is close enough, even if some further error is included. For this reason the adjust operation performs check for all upgrades, updates the delta value and then subtracts a external delta value to make room for error. The value is passed as integer 0-9 and means a subtraction of corresponding value 0.01-0.09 from ALL DELTAS.

    ->one more thing: when bot performs the adjusting process, it will do it twice, first for monkeys placed on the left side (which opens upgrade panel on right), then on right (which opens panel on left). Then it will use the lower value of the two and, after this, does the previously mentioned subtraction process. This is important as upgrade panels of different sides can give noticeably different results so lower one is used as baseline.

Monitoring

Monitoring window, with queue mode enabled. Current plan is quadHardChimps, with dark_castleHardChimps coming after.
  • Loads all settings set in other windows and initializes the bot. User can then run the bot by simply pressing "Run" button or the start-stop hotkey (which can be customized under gui hotkeys), and bot starts to search for Btd6 main menu screen. After menu screen is found, bot then begins it's current loop.

    Most settings (like resolution) and hotkey values, are updated immediately to current monitoring window. But any toggleable modes and current plan list, will only get updated after you close and reopen this window. If you want to be 100% certain your setting are up to date after any changes, just close and reopen monitoring window each time you have made changes to settings.

  • Has a output window where all printed text is redirected during bot runtime. This way, it's easy to follow what the bot is currently doing. Not all text is displayed because it would clutter the print window. To enable extra text for ocr outputs, check Settings window on advanced section and toggle delta/substring text checks on.

  • Displays current plan, and if queue mode is on, next plan in queue. Also displays any toggled modes from main window as On/Off.

  • If queue mode is enabled, uses queue discard system: when a plan is finished(*), it is removed from loaded plan queue. Then, if you stop the bot and run it again, it continues from the plan it left on and does not reset the entire queue until you close current monitoring window. When all plans are finished, run button displays "Repeat queue" instead. When you press it, plan queue resets and begins running all plans in same order again.

    (*) finished means plan was either successfully finished or it could not be completed within set amount of retries.

    • Also, when plan queue is finished, a success rate percentage is displayed. Furthermore, each plan name, their success status ("success"/"failed") and amount of attempts out of total if status is "success" are also printed.
  • Displays round timer for current round; not 100% accurate, but still quite good and very useful for adjusting ability timings when new plans are created.

  • (Optional) Just like in main window, you can add map images to replace the ascii art. If you did this step for main window, no need to do it again: same images work here.

    To do this, have map images saved in "Files/map images" folder and make sure they follow correct format:

    1. only letters and spaces allowed

    2. only lowercase letters, special characters are allowed (like # in #ouch, ' in adora's temple)

    3. image resolution is 320x195

      • you can use tools/image_scaler for this
    4. file format is png

    For example, if you wanted monkey meadow, x factor and #ouch map images, files should be named

    • monkey meadow.png

    • x factor.png

    • #ouch.png

    Map images can be downloaded from https://www.bloonswiki.com/List_of_maps_in_BTD6

Creating a new plan

Plan files are located in btd6bot/plans.

For creating and writing plans, it helps a lot if you understand basics of object-oriented programming in Python. This is not required, but some things can be be harder to understand.

Create a plan file

First, you need a plan template. One can be found in "plan_template" folder, located in project root folder. Then simply copy the map_nameDifficultyMode.py file into "btd6bot/plans" folder.

Plan file: naming

File names follow a specific standard, which was implemented long time ago to handle plan files inside gui, and has remained the same ever since:

  1. Map name:

    • spaces are replaced by underscores _. Then end of the road becomes end_of_the_road
    • special characters are allowed. So #ouch and adora's_temple are fine.
  2. Difficulty:

    • only 3 choices here: Easy, Medium or Hard.
    • it's important the difficulty is exactly as stated above: starts with capital letter and rest are lowercase.
  3. Game mode

    • same as with difficulty: first letter is capitalized, rest lowercase.
    • two modes have special syntax which include underscores: Double HP moabs and Half Cash

    Game modes for each difficulty:

    Easy Medium Hard
    Standard Standard Standard
    Primary Military Magic
    Deflation Apopalypse Double_hp
    Reverse Half_cash
    Alternate
    Impoppable
    Chimps

    (Optional) if a plan with same map, difficulty and game mode exists and you wish to make another sharing same settings, simply add number 2-9 at the end. This means you can have up to 9 different plans on same setting.
    Example: cubismHardStandard, cubismHardStandard2, cubismHardStandard3, ..., cubismHardStandard9, are all valid.

Examples for each game mode:

monkey_meadowEasyStandard.py
middle_of_the_roadEasyPrimary.py
winter_parkEasyDeflation.py

sulfur_springsMediumStandard.py
adora's_templeMediumMilitary.py
kartsndartsMediumApopalypse.py
rakeMediumReverse.py

last_resortHardStandard.py
sunken_columnsHardMagic.py
pat's_pondHardDouble_hp.py
cornfieldHardHalfcash.py
ravineHardAlternate.py
workshopHardImpoppable.py
#ouchHardChimps.py

=>a second #ouch hard chimps plan
#ouchHardChimps2.py

Plan files: info panel and round block structure

Now, open your plan file. It looks like this:

"""  
[Hero] -
[Monkey Knowledge] -
-------------------------------------------------------------
===Monkeys & upgrades required===
_______________________________________
"""

'''
from ._plan_imports import *


def play(data):
    BEGIN, END = menu_start.load(*data)
    round = BEGIN - 1
    map_start = time()
    while round < END + 1:
        round = Rounds.round_check(round, map_start, data[2])
        if round == BEGIN:
            ...
'''

First remove the two comment lines starting with ''' symbols (not the """) so bot is able to execute plan code:

"""  
[Hero]  
[Monkey Knowledge] -
-------------------------------------------------------------
===Monkeys & upgrades required===
_______________________________________
"""

from._plan_imports import *


def play(data):
    BEGIN, END = menu_start.load(*data)
    round = BEGIN - 1
    map_start = time()
    while round < END + 1:
        round = Rounds.round_check(round, map_start, data[2])
        if round == BEGIN:
            ...

This is about the minimal code needed to run a plan file. To quickly summarize what's in here:

  • Plan files start with a block of text wrapped in triple quotes """. Everything inside quotes is treated as info for current plan: it will be displayed both under main and queue windows. It consists of 4 entries:

    1. [Hero] which is the hero used for this plan. For example, if you wanted to use Quincy, you simply leave one empty space, then type Quincy:

       [Hero] Quincy
      

      Names are not case sensitive so [Hero] quincy would also work. All available heroes can be found here.
      If your plan does not need a hero, use a dash instead i.e. [Hero] -

    2. [Monkey knowledge] states if plan requires monkey knowledge. Use [Monkey knowledge] Yes if yes or [Monkey knowledge] - if not. To give information on required mk, see 4.

    3. List of required monkeys and highest crosspaths.

      Examples:

      • if plan uses 2-0-5 sniper and 0-5-2 sniper, then you would type sniper 2-5-5.
      • uses darts at start but doesn't upgrade them -> dart 0-0-0
      • uses multiple 0-0-4 beast handlers to merge and create a 0-0-5 beast-> beast 0-0-5

      All examples combined, info sections would look like this:

       ===Monkeys & upgrades required===
       dart 0-0-0
      
       sniper 2-5-5
      
       beast 0-0-5
      

      You can write all the requirements without separating categories, but in above example, primary/military/support are separated by empty line each.

    4. General info: here you can write anything you'd like the user to know about e.g. monkey knowledge requirements (list them or give a general explanation) or just comment something. Example:

       ===Monkeys & upgrades required===
       .
       .
       .
       _______________________________________
       this is a test plan and this is a comment
       comments can span multiple rows
      

      Text will auto-wrap in gui menu so, while not recommended, you could also just write all of this on a single row.

    With sections 1.-4. combined, here's a simple info text example:

      [Hero] Quincy
      [Monkey Knowledge] -
      -------------------------------------------------------------
      ===Monkeys & upgrades required===
      dart 0-0-0
    
      sniper 2-5-5
    
      beast 0-0-5
      _______________________________________
      this is a test plan and this is a comment
      comments can span multiple rows
    

    For better examples, you should check other existing plans in plans folder.

    Info will also display current plan file name without the .py suffix, and current game version value if it exists. To set a version value, you need to open Settings and

    • Enable "Record round times and update plan version"
    • Set "Game version" to current bloons td 6 version. Only the major version number is accepted as integer: if version would be 50.2, just insert 50 and press "Update version".
    • Then, let bot run and finish the plan to verify it can be completed, and it will auto-update version number for that plan.

Now that you know what the info panel is, let us have a look at the main body:

from._plan_imports import *

def play(data):
    BEGIN, END = menu_start.load(*data)
    round = BEGIN - 1
    map_start = time()
    while round < END + 1:
        round = Rounds.round_check(round, map_start, data[2])
        if round == BEGIN:
            ...

This block is Python code. It includes

  • all required imports: these are mostly the commands you will use to write bot actions
  • play function which is called for each plan
  • initialization through menu_start.load; select hero, map, difficulty and game mode
  • set a starting point to track total time
  • and finally, the main round loop: this begins from round BEGIN (value depends of difficulty and game mode) and continues until you finish final round (reach END+1). After it does checks and updates "round" value, it matches this to corresponding if/elif block to perform command for that round.

Thus, you only need to interact with the part starting from

    if round == BEGIN:
        ...

Note that BEGIN is a variable: YOU DON'T NEED TO CHANGE THIS VALUE, it will always stand for first round.

Usually you have multiple rounds which means rounds look like this:

    if round == BEGIN:
        ...
    elif round == 7:
        ...
    elif round == 10:
    .
    .
    .
    elif round == 99:
        ...

Previous block could serve as chimps mode plan template: here BEGIN stands for 6. Note that if nothing happens during a round, you can exclude it from if/elif: here rounds 8 and 9 are skipped over. For final round you can just use the round number or variable END:

    elif round == 100:
        ...

    # or

    elif round == END:
        ...

Again, no need to include final round block if it has no commands.

On two special cases, you can just use the first if-block

    if round == BEGIN:
        ...

to include all commands. These are deflation and apopalypse. In fact, for apopalypse, you have to use only the first round block!. After first round ends, bot sets internal flag for end round and stops processing other rounds.

For examples see dark_castleEasyDeflation.py and infernalMediumApopalypse.py plan files.

Commands

With commands you can make bot to do stuff during rounds.

For now, you can ignore cpos argument: it's mostly needed for maps with changing positions e.g. Geared and Sanctuary. There are also other important topics you should be aware of; all of them are explained later in Advanced section.

For string/text values, Python allows you to use both

  • double quotes "dart", or
  • single quotes 'dart'

Double quotes is the default this document uses because these are also used outside plan files. But there's nothing wrong with single quotes.

For practical examples, check any plan file in btd6bot/plans folder.

Monkeys

Command (with arguments) Description Examples
Monkey(name, pos_x, pos_y) Places a monkey name at location (x, y). To access commands, store it in a variable with recognizable name.
All supported monkeys can be found here.
dart = Monkey("dart", 0.5, 0.5) 
heli1 = Monkey("heli", 0.1, 0)
target(set_target, x, y, cpos) Change monkey targeting to set_target. For non-targetable monkeys, simply enter the target string.
For target options with target coordinate (x, y), pass x and y values.
All possible targeting options are listed here.
dart.target("strong")
heli1.target("lock", 0.1, 0.15)
upgrade(set_upg, cpos) Upgrade a monkey. Upgrades are given as a list of strings set_upg of form "t-m-b" where t=top, m=middle, b=bottom
path i.e. they follow the usual path standard. Multiple upgrade can thus be queued in one call.
Make sure path is valid: cannot do ["0-0-1", "0-0-3"].
dart.upgrade(["1-0-0"]) 
dart.upgrade(["2-0-0", "2-1-0", "3-1-0"])
special(s, x, y, cpos) Use special ability 1 or 2. Thus, s is either 1 or 2. If targetable special, give also x and y for target location.
Is required for moving mortar and dartling location. Special 2 is rarer: some uses would be beast handler second
crosspath beast location and (for heroes) Rosalia replace location.
heli.special(1, 0.1, 0.1) 
mortar.special(1, 0.1, 0.1)
dartling.special(1, 0.5, 0.785)
sniper.special(1)
beast.special(2)
sell(cpos) Sells current monkey. On code level, object still exists so please don't refer to it afterwards, unless you've inserted
another non-sold monkey in same variable.
dart.sell()
target_robo(direction, clicks, cpos) Change second arm targeting of a robo monkey. Current targeting value must be tracked manually: then, you simply
pass direction as "left" or "right" to click either left or right arrow direction and give amount of clicks to
this direction. For example, after placing a robo monkey, if first hand is on "first" then second is set on "last". Clicking
left arrow once changes it to "close". And clicking right once would change it back to "last".
super.target_robo("left", 2)
merge(x, y, cpos) Merge this beast with another at location (x, y) i.e. target beast gets the benefit of merging, this one becomes idle.
beast.merge(0.5, 0.5)
center(x, y, cpos) Change x-x-2+ ace center path location to (x, y).
ace.center(0.45, 0.35)

Heroes

Command (with arguments) Description Examples
Hero(pos_x, pos_y) Places a hero at location (x, y). To access commands, store it in a variable with recognizable name.
All available heroes are listed here.
hero = Hero(0.5, 0.5)
target
special
sell
Works exactly the same as with Monkey, see the table above.
hero.target("last")
hero.special(2, 0.1, 0.1)
hero.sell()
force_target() Currently, only use is to update internal targeting flag for bot when Etienne hits level 11: because bot is unable to
track hero xp, it cannot auto-update current targeting mode to zone control. If you use Etienne and plan to change his
targeting after lvl 11, you must call this command at the beginning of the round he reaches this milestone; otherwise
bot and game have different targeting value which will most likely cause issues.
hero.force_target() 
shop(item, target_x, target_y, cpos) Use Geraldo's shop item at location (target_x, target_y). Item is given as an integer 1-16: first item being top left,
last being bottom right, order of items is left to right, top to bottom. This means first row is items 1-4, second 5-8,
third 9-12, fourth 13-16
hero.shop(10, 0.5, 0.5)
spellbook(spells, cpos) Use Corvus's spellbook. Similar to Geraldo's shop, but spells takes a list of integers 1-16; order still the same
(left to right, top to bottom). You can pass multiple integers to chain spells.
hero.spellbook([1])
hero.spellbook([20, 6, 2, 3])

General

Command (with arguments) Description Examples
ability(key, timer, xy, delay) Press ability hotkey 1-10, after timer seconds has passed, at tuple location xy, with optional delay value.
Abilities order depend on the order they get unlocked; keep this in mind!Timer value is counted as seconds and is a float number.
It defaults to 0 and uses ability instantly the moment bot reads the command. If timer value N > 0, bot wait N seconds from
round start before using the ability.
However, if time since round start has already exceeded the N, ability is obviously used instantly when command is read
e.g. ability(1,10) uses ability 1 instantly if, say 15 seconds have passed. If ability requires a target (e.g. engineer overclock),
pass it as a tuple value xy=(x,y), NOT as separate x and y.
Finally, delay uses ability, waits for delay amount (measured in seconds), then moves cursor over to location xy. Its only reasonable
use is to refresh Obyn's trees, wait the delay amount to let bananas finish their moving animation, then move cursor to tree location
to collect them. You can just also achieve this by setting a wait timer, then use move_cursor command at tree location.
Importantly delay has default value of 0, which actually disables the cursor moving: any value greated than 0 enables it!
ability(1)
ability(3,10)
ability(2,xy=(0.25, 0.25))
ability(1, 5, (0.1, 0.1), 1)
wait(timer) Pauses any bot commands for timer amount of seconds, then resumes after.
wait(10)
click(x, y, N) Left mouse click at target location (x, y), N times. Useful for interracting with map elements. Default for N is 1, usually this suffices.
Exception would be Ravine where sword needs to clicked 23 out of total 24 to prepare it.
click(0.3, 0.4)
click(0.05, 0.12, 15)
move_cursor(x, y) Move mouse cursor to target location (x, y). Rarely useful. Similarly to ability, you could use it to collect bananas from Obyn's
tree.
move_cursor(0.75, 0.44)
forward(clicks) Click the forward button on bottom right clicks times, which gets value 1 or 2 times. Default is 2, which sets the game on fast
forward.
If you play on apopalypse, game already start on basic speed so forward(1) sets it on fast.
Important You don't need to insert this command inside first round block, as bot will automatically call it if it has not
been called yet. On some harder maps however, you might need to do initial placements, then buy another
monkey/change targeting midround. For this, write the initial commands, then add forward call, then add rest of the commands
forward(1)
forward(2)
change_autostart() Changes current autostart status: if you have autostart enabled, this will disable it, and vice versa.
Used mostly for advanced/expert chimps. Using this effectively can make your advanced/expert plans much safer (=less rng)
and some plans just require it and cannot be completed otherwise.
change_autostart()
end_round(timer) Pressed the start/forward button a single time after timer amount of seconds has passed; supports float values. If no timer value is
given, defaults to 0 seconds. Only used when autostart is disabled with change_autostart(). You can see this used often under expert
chimps plans, because with autostart disabled rounds need to be ended manually.
end_round(20)

Advanced

These topics are more difficult to grasp, but necessary for creating more complex plans.

  • [cpos] cpos updates current x and y positions. If map such as Geared moves your monkey location from previous and you need to call a command on this monkey, cpos must be used. Otherwise bot thinks the monkey is still at previous location which of course will break it. To use cpos, simply add cpos=(x, y) argument at the end and insert the new location coordinate.

    • Note that cpos will also update this as current coordinate, so if monkey has not changes it's position since last cpos command, you don't need to add them again.

      An example could be Geared map: you place a monkey at location (x,y) then 8 rounds pass and gear has done full rotation and landed on same coordinate. Then, updating cpos is not needed because bot already points at this location.

      But, for safety/good practise measures, you should still always add them on Geared/Sanctuary plans: makes easier to go back and check for possible errors.

    To see how cpos is used in practise, check sanctuaryHardChimps.py or gearedHardChimps.py plan files.

  • [placement_check] When you create a Monkey object, there's another parameter called placement_check. It defaults to boolean value True which means bot will perform the usual check as intended. But, on some occasions, you might want to avoid this: if you place towers close to upper hud i.e. under hp, cash or round display, changes are you cannot click the monkey at same location you initially placed it at. This is because those hud values can change and block the access. If access is blocked, bot cannot verify the placed monkey and this is likely to break the plan execution.

    To avoid this, you can pass placement_check=False which ignores the checking process e.g. dart1 = Monkey("dart", 0.1, 0.1, placement_check=False). Then, you use cpos to update the location where this monkey is accessed from: you click slightly off the center and it should still count as clicking on this monkey. Then just set this new position as cpos when you next need to command said monkey.

    While this process is often an overkill and can be avoided by changing placements further away from hud, one actual use case is found in bloody_puddlesHardChimps plan: here, a sniper is placed at the top left position, next to left outermost track, to provide best coverage for early game. The position is just under the cash display: sniper can be placed normally, but cannot be clicked and accesed again at same location. Thus following commands are performed:

      sniper3 = Monkey("sniper", 0.1619791666667, 0.0268518518519, placement_check=False)
      sniper3.target("strong", cpos=(0.1291666666667, 0.0601851851852))
    

    Here, as you can see, sniper ignores the placement check, and next target command updates the (x,y) position of sniper by moving slightly left and up from initial x and y coordinates.

  • [Order of arguments] In command examples, commands often exclude the argument names. For example

      dart = Monkey("dart", 0.5, 0.5)
    

    is the same as

      dart = Monkey(name="dart", pos_x=0.5, pos_y=0.5)
    

    Reason is, if you use arguments in order, arg_name= syntax is not needed: Python knows that, in above example, "dart" refers to argument name, the first 0.5 value refers to pos_x and second to pos_y.

    However, if you ever need to access latter arguments without using all the previous ones, you have to use actual argument keyword. For example, in map Geared, you placed a dart monkey, just like in code above. Now, you want to change its "first" to "strong", but to do this, you need to update its current position because gear has moved since it's initial placement. So maybe the new position is (0.45, 0.3). To update dart position, the cpos argument is needed. Now, target command has syntax target(set_target, x, y, cpos) which means if you write

      dart.target("strong", 0.45, 0.3)
    

    this will actually just click dart's current internal location (0.5, 0.5) and try to set monkey at that location on "strong". Well there could be a monkey, or not. Nontheless, it's not the intended outcome! After this, it will attempt to target dart location (0.45, 0.3); again, this doesn't mean anything for current 0-0-0 dart!

    The problem? Just as stated at the first example, this argument means

      dart.target("strong", pos_x=0.45, pos_y=0.3)
    

    Because x and y values are not needed for dart, command needs to be provided with argument names:

      dart.target("strong", cpos=(0.45, 0.3))
    

    This would do what we originally wanted. Of course, something like

      dart.target("strong", 0.2, 0.3, 0.45, 0.3)
    

    would also work in sense, because it does the same as

      dart.target("strong", pos_x=0.2, pos_y=0.3, cpos=(0.45, 0.3))
    

    but again bot would set the target location of 0-0-0 dart at (0.2, 0.3). Luckily, it would cause no harm, but is not what was intended.

    To summarize: if you use all arguments up to a point, no need to add argument names. But if you skip over even one, rest of the arguments must use argument names. This might be difficult to understand at first, but with practise and using existing plans as examples, it becomes easy to remember.

  • [Possible round detection issues] If you have lot of things happening under the round label top right, bot might sometimes have issues with detecting rounds: this can either result into delayed round start OR it can even skip over rounds because bot will falsely detect it has falled behind in rounds and tries to catch up. This rarely becomes a problem, but if it happens, it could cause serious issues, as bot uses abilities before their intended rounds/timings.

    A good example of this would be Erosion map: here, lot of end game defense is likely concentrated in the remaining ground located top right. Not only this, all bloons move around this area during final rounds as well. Combined, bloons and lot of projectiles flying around round text might create detection issues.

    So just be aware that this issue can exist, but majority of time you don't need to concern yourself with it!

Tables: Monkeys, heroes and targeting options

Monkey names

Use these values when placing a new monkey with Monkey(name, pos_x, pos_y) command

Primary Military Magic Support
dart sniper wizard farm
boomer sub super spike
bomb boat ninja village
tack ace (1) alch engineer
ice heli druid beast
glue mortar mermonkey
desperado dartling

1: If you plan to use wingmonkey monkey knowledge, see Targeting (2).

Heroes

Hero for current plan is selected based on [Hero] value inside the plan file info panel.
In the following table, Heroes are categorized by their xp ratio. Higher ratio means slower xp gain.

x1 x1.425 x1.5 x1.71
Etienne (1) Brickell Benjamin Adora
Geraldo Corvus Psi Churchill
Gwen Ezili Silas
Obyn Pat
Quincy Rosalia
Striker Sauda

1: When Etienne hits level 11, he auto-updates targeting mode from whatever you currently use to "zone control". If you plan to change Etienne's targeting afterwards, you must call force_target() on same turn as Etienne levels up to 11. This command sets bot targeting internally to "zone control". Otherwise game and bot have different targeting values which will most likely cause issues.

Targeting

Use target(set_target, x, y, cpos) to change targeting.

Basic (1) heli ace sniper mortar (4) dartling spike (6)
"first" "lock" (5) "circle" "elite" (3) "locked" (5) "normal"
"close" "pursuit" "infinite" "set"
"last" "eight" "close"
"strong" "centered" "smart"
"wingmonkey" (2) "automatic"

1: Valid for most monkeys/heroes. Also, x-x-3+ ice, 5-x-x tack and 5-x-x village can use these.

  • For x-3+-x super, use target_robo command to control second arm targeting.

2: To enable wingmonkey mk, first ace must be named ace_wing instead of ace. This enables a global flag to take wingmonkey into account with targeting changes; without the flag enabled, actual target value and bot value are going to be desynced.
Afterwards, you place aces normally using ace.

3: When a x-5-x sniper is bought, a global flag tracking elite targeting is set to True. Bot can then automatically adjust targeting system around elite targeting. And, when x-5-x sniper is sold with sell(), this status is reverted back to False.
After selling bot automatically keeps track of any targeting changes caused by losing elite targeting option.

4: Mortars cannot be targeted using target command. Use special(1, x, y) instead.

5: Dartling guns behave a bit differently and require both target and special commands for (re)targeting. Some other monkeys, like heli can benefit from this as well.

  • For dartling, use target("locked", x, y) the first time to set direction.
  • For heli, bot automatically calls target("lock", x, y) the first time to set hover position to where helipad was placed.

To retarget either of monkeys in their locked state, you must use special(1, x, y) instead. This is because bot has been programmed to require new targeting value to be different from current e.g. you can't set a monkey on first if it already has this value. Therefore, when trying set dartling/heli to locked/lock respectively, same rule applies.

6: Requires x-x-2+ spike. With set, you can set initial location with target("set", x, y) and must use special(1, x, y) afterwards.

Updating the bot

This section covers how to add new content for BTD6bot.

Some Python knowledge is required. You should also use a code editor like VS Code for optimal experience.


btd6bot source should look like this:

_ocr_tests
bot
Files
gui
plans
utils
__init__.py
__main__.py
_no_gui.py
set_plan.py

For in-game updates only bot and Files are necessary, as only somewhat frequent additions would be new monkeys and heroes.

  • Maps don't require any changes because bot selects a map using the plan file: if a new map called Bloons Map was added and you wanted to create a plan for it on hard, standard then simply name the plan file bloons_mapHardStandard.py.

  • For major changes, like new additions to game's ui, some bigger changes in bot code could be required. However, because changes like these are too vague to be described under a ruleset, they are not covered here and each case must be handled individually.

Bot and files directory can be summed shortly:

  • bot contains the entire bot library which is responsible of all in-game bot actions. It includes the logic for menu navigation, round and defeat checks, time flow, keyboard and mouse controls, text detection and reading etc. It also implements all bot commands used in plan files.

  • Files includes all non-Python files gui and bot need. Only upgrade ocr template and hotkeys need to be updated.

So only files you likely need to modify are

  • bot
    • locations.py
    • _adjust_deltas.py
    • commands/monkey.py
    • commands/hero.py
  • Files
    • _ocr_upgradedata.json
    • text files/hotkeys.txt
    • custom_locations.json

New monkeys

  1. Monkey name

    • open bot/commands/monkeys.py

    • under Monkey class, find _MONKEY_NAMES constant.

    • add monkey name here. Each category is on its own line; hero is just a identifier for hero-type monkeys. Make sure name is short, written as lowercase string (add double quotes " " around it) and related to actual monkey. It will be used in multiple places, in particular each time a monkey of this type is created.

    Example: if your monkey is called "test_monkey" and it belongs to military category, then code becomes

     _MONKEY_NAMES = (
     "dart",  # primary
     "boomer",
     "bomb",
     "tack",
     "ice",
     "glue",
     "desperado",
     "sniper",  # military
     "sub",
     "boat",
     "ace",
     "heli",
     "mortar",
     "dartling",
     "test_monkey",
     "wizard",  # magic
     "super",
     "ninja",
     "alch",
     "druid",
     "mermonkey",
     "farm",  # support
     "spike",
     "village",
     "engineer",
     "beast",
     "hero",  # hero
    

    )

    Don't forget to add comma , at the end of each row, except the last "hero" row!

  2. Set hotkey

    • open Files/text files/hotkeys.txt and add a new row:

      • first, name of the monkey e.g. test monkey
      • then, one space, followed by = then another space
      • then, set an initial hotkey value; user sees this in gui. Some existing symbols can display weirdly when you edit this file manually: make sure to update these through gui.

      Lets say you used just q as hotkey. Then simply write test monkey = q.

    • in bot/commands/monkeys.py, search _get_hotkey and support for new hotkey:

        case "test_monkey":
            return hotkeys["test monkey"]
      

    Here,

    • use the code-level name you added in _MONKEY_NAMES inside case e.g. case "test_monkey"
    • hotkey string you wrote in hotkeys.txt inside hotkeys[...]; remember to add " " to use string type e.g. hotkeys["test monkey"].
  3. Add targeting settings

    • in monkeys.py, search _change_target
    • add a case for your monkey
    • add all possible targeting outcomes: target value is the one you are switching to, current is current value before switching to target.

    Some monkeys like sniper and ace have more complex systems, because the amount of key presses to move from current to target depends on what targeting options are currently available. For snipers, x-5-x unlocks elite; for aces, x-x-2+ unlocks centered and possible monkey knowledge unlocks wingmonkey.

  4. Add possible automatic update of target values

    For most monkeys, this one is not required. Only for monkeys which auto-switch to a targeting option after upgrading. Examples: heli 2-x-x-, ace x-x-2, sniper x-5-x. To add a new value:

    • in monkeys.py, search _update_auto_target_paths

    • then simply add a new line like this:

        if self._name == "test_monkey" and i == 0 and int(u[2*i]) == 4:
            self._targeting = "strong"
      

    Here,

    • i == ... stands for the upgrade path: 0 for top, 1 for middle, 2 for bottom.
    • int(u[2*i]) points to upgrade path position value i.e. the crosspath value 0-5. In example above, i == 0 and int(u[2*i]) == 4 means top path 4. upgrade, or 4-x-x path.

    Together, code above states: if "test_monkey" is upgraded to 4-x-x, change targeting to strong.

  5. Set basic targeting value

    • in monkeys.py, search _basic_monkey_targeting
    • again, add a new case for your monkey and its default targeting when its initially placed. If targeting value is first, close, last or strong, don't add anything, case _ covers this.
  6. Add any command methods

    Again, optional for most monkeys. But if your monkey requires some custom command, add method for it. Add these at the bottom of monkeys.py. Examples for current monkeys:

    • robo_target: for super monkeys only, in particular robo monkeys. Change second arm targeting.
    • merge: merge this beast handler with another located in target location.
    • center: change a x-x-2+ ace center path location.
  7. Update upgrade ocr base values (VERY IMPORTANT)

    In order to include the new monkey in ocr adjusting, you need to add all its upgrade paths, upgrade names and placeholder deltas to Files/_ocr_upgradedata.json. This data must be similar to existing entries: for example, dart monkey has its data listed something like this:

     "dart 1-x-x": [
       "sharp shots",
       0.5
     ],
     "dart 2-x-x": [
       "razor sharp shots",
       0.5
     ],
     .
     .
     .
     "dart x-x-4": [
       "sharp shooter",
       0.5
     ],
     "dart x-x-5": [
       "crossbow master",
       0.5
     ]
    
    1. each dictionary key is a string of monkey name and upgrade crosspath: each such string forms a key
    2. under each key is a list object with 2 entries.
      • first is upgrade path name; copy the names from in-game upgrades and try to avoid typos: one wrong letter is mostly fine, but multiple can cause problems with ocr.
      • second is delta value: because this file is just a template, these are just default placeholder values. The actual file which is created during ocr adjusting process copies these to initialize fields, then updates them immediately after with real data. Just insert a valid value like 0.5, then copy-paste it under other upgrades as well.

New heroes

  1. Hero click location in selection screen

    • open bot/locations.py

    • under "CLICK" dictionary, there are dictionaries "heroes" and "heroes2": these contain hero portrait click locations for each hero when in selection screen. Then,

      • If hero can be accessed without needing to scroll the selection screen down, it should be added in "heroes".
      • Otherwise, hero is initially hidden and screen must be scrolled down to reveal it. Currently, only corvus requires this, thus located under "heroes2".
    • then, get the hero portrait location with coordinate tool (tools/show_coordinates) and add a new entry to one of the lists: it needs to include

      1. hero name, all lowercase, and
      2. click location as a tuple.
        Note that hero locations can change between updates so you might need to change location of other heroes as well.
    • (optional) update hero dictionary in Files/custom_locations.json

This in in fact the only mandatory step for adding heroes. However, if hero uses custom targeting options (other than first, close, last, strong) or requires custom commands (Geraldo's shop, Corvus's spellbook) then read the following sections.

  1. Custom targeting options

    • open bot/commands/hero.py

    • search for method _change_hero_target and find following part (or something that looks very similar to it in case this has not been updated) under it:

        match self._hero_name:
            case "benjamin":
                print("???")
            case "etienne":
                if target == "d&q":
                    if current == "first":
                        kb_mouse.kb_input(hotkeys["target change"])
                    elif current == "zone":
                        kb_mouse.kb_input(hotkeys["target reverse"])
                elif target == "first":
                    if current == "d&q":
                        kb_mouse.kb_input(hotkeys["target reverse"])
                    elif current == "zone":
                        kb_mouse.kb_input(hotkeys["target change"])
                elif target == "zone":
                    if current == "first":
                        kb_mouse.kb_input(hotkeys["target reverse"])
                    elif current == "d&q":
                        kb_mouse.kb_input(hotkeys["target change"])
                else:
                    return self._name, target
            case _:
                return self._normal_targeting(current, target) 
      

      Here the special cases: all other heroes operate under basic system.

      • For benjamin, no case would be required: all it does currently is to print text ??? if user tries to change targeting.

      • For Etienne however, system matches to new target value target, then jumps into if-elif block to see current targeting setting and presses target change/reverse keys desired amount of times: in this particular case, only a single key press is required which is already the default value.

      IMPORTANT Bot cannot track hero xp and thus is unable to know current level of hero. If hero unlocks a new targeting setting on some level, like Etienne does, following happens:

      • in-game, when Etienne reaches lvl 11, targeting is automatically set to zone control. For bot, it should also become zone, but this cannot happen automatically for the reason stated. Thus, to sync targeting between game and bot, user must call force_target method in any plan that includes Etienne reaching lvl 11. All this method does is it sets self._targeting = zone which means bot is now in sync game targeting. Afterwards, targeting works as expected.

      If any hero behaves similarly, add an internal flag by editing force_target method and notify the user which heroes require this under by adding a comment in Heroes .

  2. Custom commands for a hero

    If you need to add custom command(s) for any hero:

    • add a new method, name it in a way that describes it well, but is relatively short (e.g. shop for Geraldo, spellbook for Corvus)
    • implement any other required internal methods (e.g. _prepare_hero_menu for Geraldo and Corvus)
    • (Optional) Add pause flag, cpos checks so method can be used in maps with changing positions; see other existing methods for examples.

Contributing to project

[Pull requests]

Always set pull requests to merge from your branch into BTD6bot dev branch, i.e.

base: dev <- compare: your_branch

where your_branch should be main branch of forked BTD66bot repo.

This is because

  • dev is meant for adding and testing new features. Pull request code can be checked, possible fixes can be made and then all of it can be merged with current development code to make sure everything works. After current set of new features/fixes in dev branch have been tested thoroughly, only then it gets moved to main branch so that all users can access them and expect minimal bugs.
  • main is the production/user branch. It's the current version of bot all users should download and therefore must have minimal amount of bugs. Any undetected bugs can be hotfixed and tested again in dev branch then merged into main only by creating a new pull request. This way unfinished dev code and production code are strictly separated.

[Issues]

  • State your issue in your own words. If possible try to explain what you did before the issue happened. No need to be super-detailed, just the general details are enough.
  • If there was an error message or other type of text that indicates this wasn't supposed to happen, please include it.
    • Mention your operating system. Usually this can easily be interpreted from the context but not always.

About

Automation tool for Bloons TD 6 with a simple graphical user interface.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Python 100.0%