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
areastringThe area where the bot should operate. On level 1 defaults to "Stony Plains".
healthPotionThresholdfloatHealth percentage (0.0 to 1.0) at which to start drinking potions. Set to 0 or negative to disable potions.
autoEquipboolWhether the bot should automatically equip better gear.
autoAttackboolWhether the bot should automatically attack enemies.
autoLootboolWhether the bot should automatically loot items.
lootFilterPredicate<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
// Just call Idle() to use the basic bot
Idle();Idle("Crimson Meadows");Idle(healthPotionThreshold: 0.3f);Idle(healthPotionThreshold: 0, autoEquip: false);// 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(10))
{
return; // Currently fighting an enemy
}
}
// Don't loot if inventory is almost full
if (autoLoot && Character.Inventory.Container.TotalItemsWeight < Character.CarryingCapacity * 0.9f)
{
// 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, 10);
if (item != null)
{
// go to and pick up the item, return false until the item is picked up
var itemAmount = item.Amount;
var itemName = item.name;
PickUp(item, () => Log($"Found {(itemAmount > 1 ? $"<color=#FFAA00>{itemAmount}</color>" + " " : "")}<color=#{item.GetColor().ToHexStringRGB()}>{itemName}</color>!"));
//if (PickUp(item)) // go to and pick up the item, return false until the item is picked up
{
// Log($"Found {(item.Amount > 1 ? $"<color=#FFAA00>{item.Amount}</color>" + " " : "")}<color=#{item.GetColor().ToHexStringRGB()}>{item.name}</color>!"); // 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 < 8 ? "Crimson Meadows" :
Level < 11 ? "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}");
// }
bool equip = Equip(item);
if (equip)
{
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}");
// }
bool equip = Equip(item);
if (equip)
{
i--;
continue;
}
}
}
}
}
}
}