Filters Guide
PowBot Filters Guide
⚠️ API VERSION WARNING
This guide describes filter patterns and concepts that remain consistent.
Specific filter field names and method signatures may have changed.
Always verify current filter fields and methods in pow://api/reference.
Last pattern update: 2025-11-21
A comprehensive guide to using filters in the PowBot Desktop Lua API for querying and filtering game entities.
Table of Contents
- Filter Pattern Overview
- Common Filter Fields
- API-Specific Filters
- Filter Combinations
- Performance Tips
- Common Patterns
- Debugging Filters
- Empty vs Nil Filters
Filter Pattern Overview
PowBot uses a consistent filter pattern across all APIs. Filters are Lua tables that specify search criteria for finding game entities like NPCs, game objects, ground items, inventory items, and players.
The Basic Pattern
Most find methods accept an optional filter table:
-- General pattern
api:find_all(filter) -- Find all matching entities
api:find_first(filter) -- Find first matching entity
api:find_nearest(filter) -- Find nearest matching entity (spatial APIs only)
When to Use Each Method
find_all: Returns an array of all matching entities. Use when you need to process multiple results.find_first: Returns the first matching entity ornil. Faster thanfind_allwhen you only need one result.find_nearest: Returns the closest matching entity to the local player. Only available for spatial entities (NPCs, GameObjects, GroundItems, Players).
Common Filter Fields
These filter fields are available across multiple APIs with consistent behavior.
Name Filters
name - Exact Match
Matches entities with exactly this name (case-insensitive).
-- Find NPCs named exactly "Cow"
local cows = npcs:find_all({ name = "Cow" })
-- Find items named exactly "Bones"
local bones = inventory:find_all({ name = "Bones" })
name_contains - Substring Match
Matches entities whose name contains the substring (case-insensitive).
-- Find all objects with "tree" in the name
local trees = game_objects:find_all({ name_contains = "tree" })
-- Find all ore in inventory
local ores = inventory:find_all({ name_contains = "ore" })
-- Find any pickaxe equipped
local pickaxe = equipment:find_first({ name_contains = "pickaxe" })
name_matches_regex - Regex Pattern Match
Matches entities using a case-insensitive regular expression pattern. Powerful for complex name matching.
-- Find items named "Cowhide" OR "Bones" OR "Raw beef"
local loot = ground_items:find_all({
name_matches_regex = "Cowhide|Bones|Raw beef"
})
-- Find any stamina potion with charges (1-4)
local stamina = inventory:find_first({
name_matches_regex = "Stamina potion\\([1-4]\\)"
})
-- Find logs ending with "logs" (Oak logs, Willow logs, etc.)
local logs = inventory:find_all({
name_matches_regex = ".*logs$"
})
Important: In Lua strings, backslashes need to be escaped. Use \\ for regex special characters:
"\\("for literal("\\)"for literal)"\\."for literal."\\d"for digit matching
exclude - Exclusion-Based Filtering
Exclude entities matching the criteria in the nested filter table. The exclude table accepts the same filter fields as the main filter, and uses AND logic (all criteria in exclude must match for exclusion).
-- Find all NPCs except cows
local npcs = npcs:find_all({ exclude = {name = "Cow"} })
-- Find items that don't contain "ore" in name
local items = inventory:find_all({ exclude = {name_contains = "ore"} })
-- Find objects excluding specific names
local objects = game_objects:find_all({
exclude = {name_any = {"Tree", "Rock", "Door"}}
})
-- Find items excluding specific IDs
local items = inventory:find_all({ exclude = {ids = {995, 996, 997}} })
-- Complex: exclude items matching multiple criteria
local items = inventory:find_all({
name_contains = "sword", -- Must contain "sword"
exclude = {name_contains = "broken"} -- But not "broken"
})
Note: The exclude table uses AND logic - all criteria in the exclude table must match for an entity to be excluded. Positive filters and exclude filters are combined with AND: an entity must match positive filters AND NOT match exclude filters.
ID Filters
id - Exact ID Match
Matches entities with exactly this game ID.
-- Find NPC with specific ID
local npc = npcs:find_first({ id = 2692 })
-- Find item by ID
local item = inventory:find_first({ id = 995 }) -- Coins
ids - Multiple ID Match
Matches entities whose ID is in the provided list.
-- Find any of several NPCs
local monsters = npcs:find_all({
ids = {2692, 2693, 2694} -- Different goblin variants
})
-- Find any food item
local food = inventory:find_first({
ids = {379, 361, 373} -- Lobster, Tuna, Swordfish
})
id_any - Multiple ID Match (Alias)
Alias for ids - behaves exactly the same way. Matches entities whose ID is in the provided list.
-- Find any of several NPCs using id_any
local monsters = npcs:find_all({
id_any = {2692, 2693, 2694} -- Different goblin variants
})
-- Find any food item using id_any
local food = inventory:find_first({
id_any = {379, 361, 373} -- Lobster, Tuna, Swordfish
})
Distance Filters
within_distance_of_local - Distance from Player
Matches entities within the specified distance from the local player.
-- Find NPCs within 10 tiles
local nearby_npcs = npcs:find_all({
name = "Cow",
within_distance_of_local = 10.0
})
-- Find ground items within 5 tiles
local nearby_items = ground_items:find_all({
within_distance_of_local = 5.0
})
within_distance_of - Distance from Specific Tile
Matches entities within the specified distance from a specific tile. Accepts an array or table format.
-- Array format: {x, y, floor, max_distance}
local items_near_target = ground_items:find_all({
name = "Cowhide",
within_distance_of = {3200, 3200, 0, 4.0}
})
-- Table format: {x = x, y = y, floor = floor, distance = max_distance}
local npcs_near_tile = npcs:find_all({
name = "Guard",
within_distance_of = {
x = 3100,
y = 3500,
floor = 0,
distance = 10.0
}
})
-- Using last known position
local last_combat_pos = { x = target:x(), y = target:y(), floor = target:floor() }
local loot = ground_items:find_nearest({
name = "Bones",
within_distance_of = {
last_combat_pos.x,
last_combat_pos.y,
last_combat_pos.floor,
2.0
}
})
API-Specific Filters
NPCs (npcs:find_all, npcs:find_first, npcs:find_nearest)
--- @class NpcFilterInput
--- @field name string | nil -- Exact name match
--- @field name_contains string | nil -- Name substring match
--- @field name_matches_regex string | nil -- Name regex match
--- @field id integer | nil -- Exact ID match
--- @field ids integer[] | nil -- List of IDs to match
--- @field within_distance_of_local number | nil
--- @field within_distance_of table | nil
--- @field not_in_combat boolean | nil -- Filter NPCs NOT in combat
--- @field in_combat boolean | nil -- Filter NPCs in combat
--- @field not_interacting boolean | nil -- Filter NPCs NOT interacting
--- @field is_interacting boolean | nil -- Filter NPCs interacting
--- @field reachable boolean | nil -- Filter NPCs reachable from player (true) or not reachable (false)
Examples
-- Find nearest idle cow
local cow = npcs:find_nearest({
name = "Cow",
not_in_combat = true,
not_interacting = true,
within_distance_of_local = 15.0
})
-- Find all chickens in combat (scavenging kills)
local fighting_chickens = npcs:find_all({
name = "Chicken",
in_combat = true
})
-- Find interacting NPCs (being attacked by someone)
local busy_npcs = npcs:find_all({
is_interacting = true,
within_distance_of_local = 20.0
})
Game Objects (game_objects:find_all, game_objects:find_first, game_objects:find_nearest)
--- @class GameObjectFilterInput
--- @field name string | nil
--- @field name_contains string | nil
--- @field name_matches_regex string | nil
--- @field id integer | nil
--- @field ids integer[] | nil
--- @field type string | nil -- "interactive", "boundary", "floor", "wall"
--- @field within_distance_of_local number | nil
--- @field within_distance_of table | nil
--- @field reachable boolean | nil -- Filter objects reachable from player (true) or not reachable (false)
Examples
-- Find nearest copper rock
local rock = game_objects:find_nearest({
name_contains = "Copper",
within_distance_of_local = 10.0
})
-- Find trees
local trees = game_objects:find_all({
name = "Tree",
within_distance_of_local = 15.0
})
-- Find doors (boundary type)
local door = game_objects:find_first({
name_contains = "Door",
type = "boundary",
within_distance_of_local = 5.0
})
-- Find bank booth or chest
local bank_obj = game_objects:find_nearest({
name_matches_regex = "Bank booth|Bank chest",
within_distance_of_local = 10.0
})
-- Find interactive objects
local ladder = game_objects:find_first({
name = "Ladder",
type = "interactive"
})
Ground Items (ground_items:find_all, ground_items:find_first, ground_items:find_nearest)
--- @class GroundItemFilterInput
--- @field name string | nil
--- @field name_contains string | nil
--- @field name_matches_regex string | nil
--- @field id integer | nil
--- @field ids integer[] | nil
--- @field noted boolean | nil -- Filter noted ground items (true) or unnoted ground items (false)
--- @field within_distance_of_local number | nil
--- @field within_distance_of table | nil
--- @field min_store_price integer | nil -- Minimum store price (vendor value)
--- @field max_store_price integer | nil -- Maximum store price (vendor value)
--- @field min_store_price_total integer | nil -- Minimum total store price (store_price × stack_size)
--- @field max_store_price_total integer | nil -- Maximum total store price (store_price × stack_size)
--- @field min_high_price integer | nil -- Minimum high price from Grand Exchange
--- @field max_high_price integer | nil -- Maximum high price from Grand Exchange
--- @field has_high_price boolean | nil -- Filter items with high price data available
--- @field min_high_price_total integer | nil -- Minimum total high price (high_price × stack_size)
--- @field max_high_price_total integer | nil -- Maximum total high price (high_price × stack_size)
--- @field min_low_price integer | nil -- Minimum low price from Grand Exchange
--- @field max_low_price integer | nil -- Maximum low price from Grand Exchange
--- @field has_low_price boolean | nil -- Filter items with low price data available
--- @field min_low_price_total integer | nil -- Minimum total low price (low_price × stack_size)
--- @field max_low_price_total integer | nil -- Maximum total low price (low_price × stack_size)
--- @field min_average_price integer | nil -- Minimum average price (average of high and low)
--- @field max_average_price integer | nil -- Maximum average price (average of high and low)
--- @field has_average_price boolean | nil -- Filter items with average price data available
--- @field min_average_price_total integer | nil -- Minimum total average price (average_price × stack_size)
--- @field max_average_price_total integer | nil -- Maximum total average price (average_price × stack_size)
--- @field reachable boolean | nil -- Filter ground items reachable from player (true) or not reachable (false)
Examples
-- Find bones near last kill
local bones = ground_items:find_first({
name = "Bones",
within_distance_of = {
last_target.x,
last_target.y,
last_target.floor,
3.0
}
})
-- Find mark of grace
local mark = ground_items:find_nearest({
name = "Mark of grace",
within_distance_of_local = 20.0
})
-- Find multiple loot types using regex
local loot = ground_items:find_all({
name_matches_regex = "Cowhide|Raw beef|Bones",
within_distance_of_local = 5.0
})
-- Find valuable ground items by price
local valuable_loot = ground_items:find_all({
min_high_price_total = 5000,
has_high_price = true,
within_distance_of_local = 10.0
})
Inventory (inventory:find_all, inventory:find_first)
--- @class ItemFilter
--- @field id integer | nil -- Exact item ID
--- @field ids integer[] | nil -- List of item IDs
--- @field name string | nil -- Exact name match
--- @field name_contains string | nil -- Name substring match
--- @field min_stack integer | nil -- Minimum stack size
--- @field max_stack integer | nil -- Maximum stack size
--- @field slot integer | nil -- Specific slot index
--- @field slot_range {[1]: integer, [2]: integer} | nil -- Slot range [min, max]
--- @field charges_eq integer | nil -- Exact charges
--- @field charges_gt integer | nil -- Greater than charges
--- @field charges_lt integer | nil -- Less than charges
--- @field charges_gte integer | nil -- Greater than or equal
--- @field charges_lte integer | nil -- Less than or equal
--- @field min_store_price integer | nil -- Minimum store price (vendor value)
--- @field max_store_price integer | nil -- Maximum store price (vendor value)
--- @field min_store_price_total integer | nil -- Minimum total store price (store_price × stack_size)
--- @field max_store_price_total integer | nil -- Maximum total store price (store_price × stack_size)
--- @field min_high_price integer | nil -- Minimum high price from Grand Exchange
--- @field max_high_price integer | nil -- Maximum high price from Grand Exchange
--- @field has_high_price boolean | nil -- Filter items with high price data available
--- @field min_high_price_total integer | nil -- Minimum total high price (high_price × stack_size)
--- @field max_high_price_total integer | nil -- Maximum total high price (high_price × stack_size)
--- @field min_low_price integer | nil -- Minimum low price from Grand Exchange
--- @field max_low_price integer | nil -- Maximum low price from Grand Exchange
--- @field has_low_price boolean | nil -- Filter items with low price data available
--- @field min_low_price_total integer | nil -- Minimum total low price (low_price × stack_size)
--- @field max_low_price_total integer | nil -- Maximum total low price (low_price × stack_size)
--- @field min_average_price integer | nil -- Minimum average price (average of high and low)
--- @field max_average_price integer | nil -- Maximum average price (average of high and low)
--- @field has_average_price boolean | nil -- Filter items with average price data available
--- @field min_average_price_total integer | nil -- Minimum total average price (average_price × stack_size)
--- @field max_average_price_total integer | nil -- Maximum total average price (average_price × stack_size)
Examples
-- Find item by name
local item = inventory:find_first({ name = "Bones" })
-- Find all logs
local logs = inventory:find_all({ name_contains = "logs" })
-- Find items in specific slots (first 4 slots)
local top_row = inventory:find_all({
slot_range = {0, 3}
})
-- Find item in slot 5
local slot_item = inventory:find_first({ slot = 5 })
-- Find items with minimum stack size
local big_stacks = inventory:find_all({
min_stack = 10
})
-- Find item with specific charges (Ring of dueling with 4 charges)
local ring = inventory:find_first({
name_contains = "Ring of dueling",
charges_eq = 4
})
-- Find items with at least 2 charges
local charged_items = inventory:find_all({
charges_gte = 2
})
-- Count specific items
local bone_count = inventory:count({ name = "Bones" })
local all_count = inventory:count() -- Count all items
-- Find valuable items by price
local valuable = inventory:find_all({
min_high_price_total = 10000,
has_high_price = true
})
-- Find items with price in range
local mid_value = inventory:find_all({
min_average_price = 1000,
max_average_price = 5000,
has_average_price = true
})
-- Find cheap items for dropping
local junk = inventory:find_all({
max_store_price = 100
})
Bank (bank:find_all, bank:find_first)
Bank uses the same ItemFilter as inventory:
-- Find food in bank
local food = bank:find_first({ name = "Lobster" })
-- Check if bank contains item
if bank:contains(995) then -- Check by ID
logger:info("Bank contains coins")
end
-- Count specific items in bank
local shark_count = bank:count_of(385) -- Count by ID
local food_count = bank:count("Lobster") -- Count by name
Equipment (equipment:find_all, equipment:find_first)
Equipment also uses ItemFilter:
-- Check if wearing specific item
local has_armor = equipment:find_first({
name = "Bronze platebody"
})
-- Find any equipped weapon with "sword" in name
local sword = equipment:find_first({
name_contains = "sword"
})
-- Get item in specific equipment slot
local weapon = equipment:get_item_in_slot("weapon")
local head_armor = equipment:get_item_in_slot("head")
-- Available slots: head, cape, neck, weapon, torso, shield, legs, hands, feet, ring, ammo
Players (players:find_all, players:find_first, players:find_nearest)
--- @class PlayerFilterInput
--- @field name string | nil
--- @field name_contains string | nil
--- @field name_matches_regex string | nil
--- @field within_distance_of_local number | nil
--- @field within_distance_of table | nil
--- @field combat_level integer | nil -- Exact combat level
--- @field min_combat_level integer | nil -- Minimum combat level
--- @field max_combat_level integer | nil -- Maximum combat level
--- @field is_interacting boolean | nil
--- @field not_interacting boolean | nil
--- @field is_moving boolean | nil
--- @field is_animating boolean | nil
--- @field reachable boolean | nil -- Filter players reachable from local player (true) or not reachable (false)
Examples
-- Find nearby players
local nearby_players = players:find_all({
within_distance_of_local = 15.0
})
-- Find high level players
local high_levels = players:find_all({
min_combat_level = 100,
within_distance_of_local = 20.0
})
-- Find players in combat level range
local similar_levels = players:find_all({
min_combat_level = 40,
max_combat_level = 60
})
-- Find moving players
local moving = players:find_all({
is_moving = true,
within_distance_of_local = 10.0
})
Menu Items (menu:find_item_index, menu:interact_with)
--- @class MenuItemFilterInput
--- @field action string | nil -- Action text (or pass string directly)
--- @field action_contains string | nil -- Action substring match
--- @field action_equals string | nil -- Exact action match
--- @field target string | nil -- Target text
--- @field target_contains string | nil -- Target substring match
--- @field target_equals string | nil -- Exact target match
--- @field sub_menu_action string | nil -- Open context menu with action then select this sub-menu option (e.g. item:interact({ action = "Rub", sub_menu_action = "Grand Exchange" }))
--- @field sub_menu_action_contains string | nil -- Sub-menu option substring match
Examples
-- Simple string filter (checks action)
menu:interact_with("Attack")
-- Complex filter
menu:interact_with({
action = "Use",
target_contains = "Door"
})
-- Find menu item by action
local index = menu:find_item_index({
action_contains = "Walk"
})
Filter Combinations
Filters are AND conditions - all specified criteria must match.
Simple Combinations
-- Name AND distance
local nearby_cows = npcs:find_all({
name = "Cow",
within_distance_of_local = 10.0
})
-- Name AND state
local idle_cows = npcs:find_all({
name = "Cow",
not_in_combat = true,
not_interacting = true
})
Complex Combinations
-- Multiple conditions for precise targeting
local target = npcs:find_nearest({
name = "Guard",
not_in_combat = true,
not_interacting = true,
within_distance_of = {
start_pos.x,
start_pos.y,
start_pos.z,
15.0
}
})
-- Inventory filtering with multiple criteria
local valuable_items = inventory:find_all({
name_contains = "diamond",
min_stack = 1,
slot_range = {0, 13} -- First two rows only
})
-- Player filtering with level range
local pk_targets = players:find_all({
min_combat_level = my_level - 5,
max_combat_level = my_level + 5,
not_interacting = true,
within_distance_of_local = 15.0
})
Using OR Logic with Regex
When you need OR logic (match A OR B), use name_matches_regex:
-- Find "Lobster" OR "Swordfish" OR "Shark"
local food = inventory:find_all({
name_matches_regex = "Lobster|Swordfish|Shark"
})
-- Find multiple ore types
local ores = inventory:find_all({
name_matches_regex = "Copper ore|Tin ore|Iron ore"
})
-- Find NPCs with multiple names
local monsters = npcs:find_all({
name_matches_regex = "Goblin|Imp|Spider",
not_in_combat = true
})
Manual OR Logic
For complex OR conditions that can't use regex, filter manually:
-- Find NPCs matching multiple IDs
local all_npcs = npcs:find_all({ within_distance_of_local = 20.0 })
local valid_npcs = {}
for _, npc in ipairs(all_npcs) do
local npc_id = tostring(npc:id())
-- Check if NPC ID is in our selection
for _, selected_id in ipairs(selected_npc_ids) do
if selected_id == npc_id then
if not npc:in_combat() and not npc:interacting() then
table.insert(valid_npcs, npc)
end
break
end
end
end
Performance Tips
1. Use Specific Filters First
More specific filters reduce the search space:
-- GOOD: Specific name + distance
local rock = game_objects:find_nearest({
name = "Copper rocks",
within_distance_of_local = 10.0
})
-- LESS EFFICIENT: Very broad search
local all_objects = game_objects:find_all({
within_distance_of_local = 50.0
})
2. Distance Filters are Efficient
Always use distance filters for spatial queries:
-- GOOD: Limited search radius
local npcs = npcs:find_all({
name = "Cow",
within_distance_of_local = 15.0
})
-- AVOID: Searching entire world
local npcs = npcs:find_all({ name = "Cow" }) -- No distance limit
3. Use find_first When You Only Need One
-- GOOD: Stops after finding first match
local bones = inventory:find_first({ name = "Bones" })
-- WASTEFUL: Finds all then takes first
local all_bones = inventory:find_all({ name = "Bones" })
local bones = all_bones[1]
4. Use find_nearest for Spatial Entities
-- GOOD: Efficiently finds closest
local npc = npcs:find_nearest({
name = "Cow",
within_distance_of_local = 15.0
})
-- LESS EFFICIENT: Manual distance calculation
local all_npcs = npcs:find_all({ name = "Cow" })
local closest = nil
local closest_dist = math.huge
for _, npc in ipairs(all_npcs) do
local dist = calculate_distance(npc)
if dist < closest_dist then
closest = npc
closest_dist = dist
end
end
5. Cache Filters When Reusing
-- GOOD: Define filter once, reuse
local cow_filter = {
name = "Cow",
not_in_combat = true,
within_distance_of_local = 15.0
}
-- Use it multiple times
local cow1 = npcs:find_nearest(cow_filter)
-- ... later ...
local cow2 = npcs:find_nearest(cow_filter)
-- AVOID: Recreating filter each time
local cow1 = npcs:find_nearest({
name = "Cow",
not_in_combat = true,
within_distance_of_local = 15.0
})
local cow2 = npcs:find_nearest({
name = "Cow",
not_in_combat = true,
within_distance_of_local = 15.0
})
6. Use contains for Simple Checks
-- GOOD: Efficient boolean check
if bank:contains(995) then -- Check by ID
-- Has coins
end
-- LESS EFFICIENT: Unnecessary find
local coins = bank:find_first({ id = 995 })
if coins then
-- Has coins
end
Common Patterns
Pattern 1: Combat Target Selection
function find_combat_target(npc_name, max_distance)
return npcs:find_nearest({
name = npc_name,
not_in_combat = true,
not_interacting = true,
within_distance_of_local = max_distance
})
end
Pattern 2: Loot Collection Near Last Kill
function collect_loot(last_kill_pos, loot_names)
-- Build regex from loot list: "Bones|Cowhide|Raw beef"
local pattern = table.concat(loot_names, "|")
local item = ground_items:find_nearest({
name_matches_regex = pattern,
within_distance_of = {
last_kill_pos.x,
last_kill_pos.y,
last_kill_pos.floor,
3.0
}
})
if item then
item:interact({ action_contains = "Take" })
return true
end
return false
end
Pattern 3: Resource Gathering (Mining, Woodcutting, Fishing)
function find_resource(resource_name)
local resource = game_objects:find_nearest({
name_contains = resource_name,
within_distance_of_local = 15.0
})
if resource and resource:is_visible() then
return resource
end
return nil
end
Pattern 4: Check Inventory for Multiple Items
function has_any_food()
local food_pattern = "Lobster|Swordfish|Shark|Tuna"
local food = inventory:find_first({
name_matches_regex = food_pattern
})
return food ~= nil
end
function count_all_food()
local food_pattern = "Lobster|Swordfish|Shark|Tuna"
return inventory:count({
name_matches_regex = food_pattern
})
end
Pattern 5: Equipment Validation
function has_weapon_equipped()
local weapon = equipment:find_first({
slot = 3 -- Weapon slot
})
return weapon ~= nil
end
function has_pickaxe()
-- Check equipment first
local equipped = equipment:find_first({
name_contains = "pickaxe"
})
if equipped then
return true
end
-- Check inventory
local in_inv = inventory:find_first({
name_contains = "pickaxe"
})
return in_inv ~= nil
end
Pattern 6: Bank Withdrawals
function withdraw_food(food_names, amount)
if not bank:opened() then
return false
end
for _, food_name in ipairs(food_names) do
local bank_item = bank:find_first({ name = food_name })
if bank_item then
local available = bank_item:stack_size()
local to_withdraw = math.min(available, amount)
if to_withdraw > 0 then
bank:withdraw({ name = food_name }, to_withdraw)
return true
end
end
end
return false
end
Pattern 7: Conditional Dropping
function drop_all_except_tools()
-- Keep pickaxe, axe, and tinderbox
local keep_pattern = "pickaxe|axe|Tinderbox"
inventory:drop_all_except({
name_matches_regex = keep_pattern
})
end
Debugging Filters
Problem: Filter Returns No Results
-- Log what's actually available
local all_npcs = npcs:find_all({ within_distance_of_local = 20.0 })
logger:info("Found " .. #all_npcs .. " NPCs nearby")
for _, npc in ipairs(all_npcs) do
logger:info(" - " .. npc:name() .. " (ID: " .. npc:id() .. ")")
end
-- Then apply your filter
local filtered = npcs:find_all({
name = "Your Name Here",
within_distance_of_local = 20.0
})
logger:info("Filtered results: " .. #filtered)
Problem: Case Sensitivity Issues
Remember: name and name_contains are case-insensitive, but check exact spelling:
-- These are equivalent:
local item1 = inventory:find_first({ name = "bones" })
local item2 = inventory:find_first({ name = "Bones" })
local item3 = inventory:find_first({ name = "BONES" })
Problem: Distance Filter Not Working
Ensure you're using correct tile coordinates:
local player = players:local_player()
logger:info("Player position: " .. player:x() .. ", " .. player:y() .. ", floor: " .. player:floor())
-- Then check target position
local target = npcs:find_nearest({ name = "Cow" })
if target then
logger:info("Target position: " .. target:x() .. ", " .. target:y())
local dx = target:x() - player:x()
local dy = target:y() - player:y()
local distance = math.sqrt(dx*dx + dy*dy)
logger:info("Actual distance: " .. distance)
end
Problem: Regex Not Matching
Test your regex pattern:
-- Log all item names to see exact format
local items = inventory:find_all()
for _, item in ipairs(items) do
logger:info("Item: '" .. item:name() .. "'")
end
-- Remember to escape special characters in Lua:
local pattern = "Ring of dueling\\([1-8]\\)" -- Note the double backslashes
Problem: Entity No Longer Valid
Always check if entity is still valid before using:
local npc = npcs:find_first({ name = "Cow" })
if npc and npc:is_valid() then
npc:interact({ action = "Attack" })
else
logger:warn("NPC is no longer valid")
end
Empty vs Nil Filters
Passing nil
When you pass nil as a filter, the API returns all entities (no filtering):
-- Returns ALL inventory items
local all_items = inventory:find_all(nil)
-- Returns ALL NPCs within reasonable range
local all_npcs = npcs:find_all(nil)
-- Useful for counting total items
local total_items = inventory:count(nil)
local total_items = inventory:count() -- Equivalent
Passing Empty Table {}
An empty table {} means "no criteria" and behaves the same as nil:
-- These are equivalent:
local items1 = inventory:find_all(nil)
local items2 = inventory:find_all({})
-- Both return all items
When to Use Each
-- Use nil for clarity when you want everything
function get_all_inventory_items()
return inventory:find_all(nil)
end
-- Use {} when building dynamic filters
local filter = {}
if options.specific_name then
filter.name = options.specific_name
end
if options.max_distance then
filter.within_distance_of_local = options.max_distance
end
-- filter might be {} if no options set
local results = npcs:find_all(filter)
Counting Examples
-- Count all items
local total = inventory:count()
local total = inventory:count(nil)
local total = inventory:count({}) -- All equivalent
-- Count specific items
local bone_count = inventory:count({ name = "Bones" })
local ore_count = inventory:count({ name_contains = "ore" })
Quick Reference
Common Filter Combinations
-- NPCs
npcs:find_nearest({
name = "Cow",
not_in_combat = true,
not_interacting = true,
within_distance_of_local = 15.0
})
-- Game Objects
game_objects:find_nearest({
name_contains = "Copper",
within_distance_of_local = 10.0
})
-- Ground Items
ground_items:find_all({
name_matches_regex = "Bones|Cowhide",
within_distance_of_local = 5.0
})
-- Inventory
inventory:find_first({
name_contains = "logs",
min_stack = 1
})
-- Bank
bank:find_first({
name = "Lobster"
})
-- Equipment
equipment:find_first({
name_contains = "sword"
})
-- Players
players:find_all({
min_combat_level = 50,
max_combat_level = 80,
within_distance_of_local = 15.0
})
Filter Field Summary
| Field | Type | APIs | Description |
|---|---|---|---|
name | string | All | Exact name match (case-insensitive) |
name_contains | string | All | Substring match (case-insensitive) |
name_matches_regex | string | All except Components | Regex pattern match |
id | integer | NPCs, GameObjects, GroundItems, Items | Exact ID match |
ids | integer[] | NPCs, GameObjects, GroundItems, Items | List of IDs |
within_distance_of_local | number | Spatial entities | Max distance from player |
within_distance_of | table | Spatial entities | Max distance from tile |
not_in_combat | boolean | NPCs | Filter NPCs not in combat |
in_combat | boolean | NPCs | Filter NPCs in combat |
not_interacting | boolean | NPCs, Players | Not interacting with anything |
is_interacting | boolean | NPCs, Players | Is interacting |
type | string | GameObjects | Object type filter |
min_stack | integer | Items | Minimum stack size |
max_stack | integer | Items | Maximum stack size |
slot | integer | Items | Specific slot index |
slot_range | integer[] | Items | Slot range [min, max] |
charges_eq | integer | Items | Exact charge count |
charges_gt/gte/lt/lte | integer | Items | Charge comparisons |
noted | boolean | Items, GroundItems | Filter noted or unnoted items |
min_store_price / max_store_price | integer | Items, GroundItems | Store price range |
min_store_price_total / max_store_price_total | integer | Items, GroundItems | Total store price range |
min_high_price / max_high_price | integer | Items, GroundItems | High price range (GE) |
has_high_price | boolean | Items, GroundItems | Has high price data |
min_low_price / max_low_price | integer | Items, GroundItems | Low price range (GE) |
has_low_price | boolean | Items, GroundItems | Has low price data |
min_average_price / max_average_price | integer | Items, GroundItems | Average price range (GE) |
has_average_price | boolean | Items, GroundItems | Has average price data |
*_price_total variants | integer | Items, GroundItems | Price × stack_size variants |
combat_level | integer | Players | Exact combat level |
min_combat_level | integer | Players | Minimum combat level |
max_combat_level | integer | Players | Maximum combat level |
is_moving | boolean | Players | Is currently moving |
is_animating | boolean | Players | Is currently animating |
reachable | boolean | NPCs, GameObjects, GroundItems, Players | Filter entities reachable from player position |
Best Practices Summary
- Always use distance filters for spatial queries to limit search space
- Use
find_firstorfind_nearestwhen you only need one result - Use regex for OR logic when matching multiple values
- Cache common filters to avoid recreating them
- Check if entities are valid before using them
- Log filter results when debugging
- Use
contains()methods for simple existence checks - Combine filters for precise results (AND logic)
- Use
count()for quantity checks instead of finding and counting manually - Test filters incrementally - start broad, then add criteria
Additional Resources
- API Overview - Desktop API reference
- Script Structure and Setup - Script patterns and setup
- Verify current filter fields in your PowBot API reference (
pow://api/reference).
Happy Filtering!