Table of Contents

Method Idle

Namespace
GrindFest
Assembly
GrindFest.dll

Idle(string, float, bool, bool, bool, Predicate<ItemBehaviour>)

A simple bot that handles basic combat, looting, and survival in a specified area. Call this method repeatedly to make your hero automatically fight and survive.

public void Idle(string area = null, float healthPotionThreshold = 0.4, bool autoEquip = true, bool autoAttack = true, bool autoLoot = true, Predicate<ItemBehaviour> lootFilter = null)

Parameters

area string

The area where the bot should operate. On level 1 defaults to "Stony Plains".

healthPotionThreshold float

Health percentage (0.0 to 1.0) at which to start drinking potions. Set to 0 or negative to disable potions.

autoEquip bool

Whether the bot should automatically equip better gear.

autoAttack bool

Whether the bot should automatically attack enemies.

autoLoot bool

Whether the bot should automatically loot items.

lootFilter Predicate<ItemBehaviour>

Filter which items to pick up. Default picks up better weapons, health potions and gold.

Remarks

See the following tutorials for more information:

This bot will:

  • Navigate to the specified area if not already there
  • Use health potions in two scenarios:
    • When below the specified health percentage threshold during combat
    • When health is not full and no enemies are around
  • Attack nearest enemies when health is good
  • Pick up nearby items when no enemies around
  • Run around exploring when nothing else to do
Basic Usage:
// Just call Idle() to use the basic bot
Idle();
Idle in specific area:
Idle("Crimson Meadows");
Idle but only use potions when health drops below 30%
Idle(healthPotionThreshold: 0.3f);
Idle but don't use potions and don't auto-equip items:
Idle(healthPotionThreshold: 0, autoEquip: false);
Using lootFilter to customize what items to pick up:
// A lootFilter is a function that looks at each item and decides if we should pick it up
// It returns true if we should pick up the item, or false if we should ignore it

// Pick up everything: Idle(lootFilter: item => true);

Copying the source code of this method to your own script is a good starting point for creating your own bot.

using UnityEngine;
using System;

namespace GrindFest
{
    public partial class AutomaticHero
    {
        /// <summary>
        /// A simple bot that handles basic combat, looting, and survival in a specified area.
        /// Call this method repeatedly to make your hero automatically fight and survive.
        ///
        /// </summary>
        /// <param name="area">The area where the bot should operate. On level 1 defaults to "Stony Plains".</param>
        /// <param name="healthPotionThreshold">Health percentage (0.0 to 1.0) at which to start drinking potions. Set to 0 or negative to disable potions.</param>
        /// <param name="autoEquip">Whether the bot should automatically equip better gear.</param>
        /// <param name="autoAttack">Whether the bot should automatically attack enemies.</param>
        /// <param name="autoLoot">Whether the bot should automatically loot items.</param>
        /// <param name="lootFilter">Filter which items to pick up. Default picks up better weapons, health potions and gold.</param>
        /// <remarks>
        /// See the following tutorials for more information:
        /// 
        /// This bot will:
        /// - Navigate to the specified area if not already there
        /// - Use health potions in two scenarios:
        ///   * When below the specified health percentage threshold during combat
        ///   * When health is not full and no enemies are around
        /// - Attack nearest enemies when health is good
        /// - Pick up nearby items when no enemies around
        /// - Run around exploring when nothing else to do
        /// 
        /// <example>
        /// Basic Usage:
        /// <code>
        /// // Just call Idle() to use the basic bot
        /// Idle();
        /// </code>
        /// </example>
        /// <example>
        /// Idle in specific area:
        /// <code>
        /// Idle("Crimson Meadows");
        /// </code>
        /// </example>
        /// <example>
        /// Idle but only use potions when health drops below 30%
        /// <code>
        /// Idle(healthPotionThreshold: 0.3f);
        /// </code>
        /// </example>
        /// <example>
        /// Idle but don't use potions and don't auto-equip items:
        /// <code>
        /// Idle(healthPotionThreshold: 0, autoEquip: false);
        /// </code>
        /// </example>
        /// <example>
        /// Using lootFilter to customize what items to pick up:
        /// <code><![CDATA[
        /// // A lootFilter is a function that looks at each item and decides if we should pick it up
        /// // It returns true if we should pick up the item, or false if we should ignore it
        /// 
        /// // Pick up everything:
        /// Idle(lootFilter: item => true);
        /// ]]></code>
        /// </example>
        /// 
        /// Copying the source code of this method to your own script is a good starting point for creating your own bot.
        /// 
        /// [!code-csharp[Idle](../../GrindFest/Assets/_GrindFest/Scripts/BotApi/AutomaticHero.Idle.cs)]
        /// 
        /// <list type="bullet">
        /// <item><description><see href="/tutorials/first-bot.html">Getting Started with Bots</see></description></item>
        /// <item><description><see href="/tutorials/movement.html">Creating Your First Combat Bot</see></description></item>
        /// <item><description><see href="/tutorials/classes.html">Creating a Bot with Classes (Advanced)</see></description></item>
        /// </list>
        /// </remarks>
        public void Idle(string area = null, float healthPotionThreshold = 0.4f, bool autoEquip = true, bool autoAttack = true, bool autoLoot = true, Predicate<ItemBehaviour> lootFilter = null)
        {
            if (healthPotionThreshold > 0)
            {
                // Health management - drink potions if health is low, only if we have potions
                if (HasHealthPotion())
                {
                    // if there are no enemies around and health is not full, drink potions
                    if (Health < MaxHealth && FindNearestEnemy(maxDistance: 5) == null)
                    {
                        DrinkHealthPotion();
                        RunAwayFromNearestEnemy();
                        return; // Drinking potions to full health is a priority
                    }

                    // drink potions if below threshold or continue drinking until full
                    if (Health < MaxHealth * healthPotionThreshold)
                    {
                        DrinkHealthPotion();
                        RunAwayFromNearestEnemy();
                        return; // Drinking potions is a priority
                    }
                }
            }

            if (autoEquip)
            {
                OptimizeEquipment();
            }

            if (autoAttack)
            {
                // Combat - attack enemies if health is good
                if (AttackNearestEnemy())
                {
                    return; // Currently fighting an enemy
                }
            }

            if (autoLoot)
            {
                // Use default loot filter if none provided
                if (lootFilter == null)
                {
                    lootFilter = item =>
                    {
                        // Always pick up gold
                        if (item.Gold != null)
                            return true;

                        // Always pick up health potions
                        if (IsHealthPotion(item))
                            return true;

                        // Pick up better weapons
                        if (item.Weapon != null)
                        {
                            if (Equipment.Weapon == null)
                                return true;

                            if (Equipment.Weapon.Durability?.DurabilityPercentage < 0.2)
                                if (item.Weapon.DamagePerSecond > Equipment.Weapon.DamagePerSecond * 0.8)
                                    return true;

                            if (item.Weapon.DamagePerSecond > Equipment.Weapon.DamagePerSecond)
                                return true;

                        }

                        // Pick up better armor
                        if (item.Armor != null)
                        {
                            if (Equipment[item.Equipable.Slot] == null)
                                return true;

                            if (Equipment[item.Equipable.Slot].Item.Durability?.DurabilityPercentage < 0.2)
                                if (item.Armor.Armor > Equipment[item.Equipable.Slot].Item.Armor?.Armor * 0.8)
                                    return true;

                            if (item.Armor.Armor > Equipment[item.Equipable.Slot].Item.Armor?.Armor)
                                return true;
                        }

                        // Don't pick up other items by default
                        return false;
                    };
                }

                // Looting - pick up nearby items when not fighting
                var item = FindNearestItemOnGround(lootFilter);
                if (item != null)
                {
                    if (PickUp(item)) // go to and pick up the item, return false until the item is picked up
                    {
                        Log($"Found {(item.Amount > 1 ? item.Amount + " " : "")} {item.name}!"); // make the hero say what they found and how many, taking into account stackable items like gold coins
                        return;
                    }

                    return; // Currently moving to item
                }
            }

            if (area == null)
            {
                area = Level < 5 ? "Stony Plains" :
                       Level < 10 ? "Crimson Meadows" :
                       Level < 15 ? "Rotten Burrows" :
                       "Ashen Pastures";
            }

            // Ensure hero is in the area
            if (CurrentArea?.Root.Name != area)
            {
                GoToArea(area);
                return;
            }

            // Exploration - run around when nothing else to do
            RunAroundInArea();
        }

        /// <summary>
        /// Optimize equipment by equipping the best weapon and armor from the inventory.
        /// </summary>
        public void OptimizeEquipment()
        {
            for (var i = 0; i < Character.Inventory.Items.Count; i++)
            {
                var item = Character.Inventory.Items[i];

                if (item.Weapon != null)
                {
                    if (Equipment.Weapon == null || item.Weapon.DamagePerSecond > Equipment.Weapon.DamagePerSecond)
                    {
                        // if (Equipment.Weapon != null)
                        // {
                        //     Say($"{item.name} is better DPS: {item.Weapon.DamagePerSecond} > {Equipment.Weapon.DamagePerSecond}");
                        // }
                        Equip(item);
                        i--;
                        continue;
                    }
                }

                if (item.Armor != null)
                {
                    if (Equipment[item.Equipable.Slot] == null || item.Armor.Armor > Equipment[item.Equipable.Slot].Item.Armor?.Armor)
                    {
                        // if (Equipment[item.equipable.Slot] != null)
                        // {
                        //     Say($"{item.name} is better Armor: {item.Armor.Armor} > {Equipment[item.equipable.Slot].Item.Armor?.Armor}");
                        // }
                        Equip(item);
                        i--;
                        continue;
                    }
                }
            }
        }
    }
}