This document details the architecture of the PocketTCGoBot automation system, covering the core systems, design patterns, and execution flow.
- CV (Computer Vision) System
- Four Core Registries
- YAML Loading & Configuration
- Bot Groups & Orchestration
- Account Pools
- Accounts System
- Routines
- Actions System
- Sentry System
- Execution Flow
- Design Patterns
- Architecture Strengths
Location: internal/cv/service.go
The CV service provides intelligent template matching with frame caching and multiple matching algorithms.
- Frame Caching: 100ms TTL prevents redundant screenshots
- Three Algorithms:
- SAD (Sum of Absolute Differences) - Fast
- SSD (Sum of Squared Differences) - Balanced
- NCC (Normalized Cross-Correlation) - Accurate
- Title Bar Exclusion: Automatically ignores window chrome
- Template Integration: Templates loaded from Template Registry and cached for performance
FindTemplate(templateName, config) // Find single match
FindMultipleTemplates(paths, config) // Find all at once
WaitForTemplate(name, config, timeout) // Wait until found
CheckColor(x, y, color, tolerance) // Pixel color verificationTemplates are loaded from the Template Registry and cached for performance. The service supports search regions and scaling for flexible matching.
Location: pkg/templates/registry.go
Manages image templates loaded from YAML definitions.
- Thread-safe with RWMutex
- Optional image caching layer
- Supports preloading and lazy loading
- Stores template metadata (path, scale, regions)
Location: internal/actions/routine_registry.go
Discovers and manages routine definitions from the routines/ folder.
- Recursive discovery from routines folder
- Eager loading & validation at startup (fail-fast)
- Stores compiled
ActionBuilder, sentries, configs, metadata - Supports namespacing (e.g.,
combat/battle_loop) - Separates valid from invalid routines
Location: internal/actions/registry.go
Maps action names to concrete types via reflection.
- Enables polymorphic YAML unmarshaling
- 50+ action types registered (click, sleep, if, while, etc.)
- Used during YAML parsing to create correct action instances
- Centralized registration point for all action types
Location: internal/accountpool/pool_manager.go
Registry for named account pools.
- Creates
UnifiedAccountPoolinstances from definitions - Manages multiple independent pools
- Provides pool lookup by name
- Handles pool lifecycle
Location: internal/config/loader.go
Legacy Settings.ini file loaded into bot.Config struct with 100+ fields:
- Instance configuration
- Pack preferences
- Delays and timing
- ADB paths
- S4T settings
- OCR configuration
Location: internal/actions/routine.go
routine_name: "Display Name"
description: "Purpose of this routine"
tags: ["tag1", "tag2"] # Metadata for filtering
config: # User-configurable parameters
- name: param_name
type: int
default: 10
persist: true # Save between runs
sentries: # Error handlers
- routine: error_handling/handler
frequency: 15 # Check every 15 seconds
severity: high
on_success: resume # Resume main routine if sentry succeeds
on_failure: stop # Stop bot if sentry fails
steps: # Action sequence
- action: click
template: button_name
- action: sleep
duration: 2000
- action: ifimagefound
template: popup
actions:
- action: click
template: close_button- Read YAML file
- Parse into
Routinestruct - Custom
UnmarshalYAMLhandles polymorphic steps - Each step unmarshals via action registry
- Validate all steps
- Build into executable
ActionBuilder
Location: internal/accountpool/unified_pool.go
Combines multiple account sources:
- SQL queries for account sources
- Include/exclude lists
- Watched folders for imports
- Sort methods and retry policies
Location: internal/bot/orchestrator.go
Orchestrator (global coordinator)
├─ Shared Registries
│ ├─ TemplateRegistry
│ ├─ RoutineRegistry
│ ├─ PoolManager (pool definitions)
│ └─ EmulatorManager
└─ BotGroups (multiple independent groups)
└─ BotGroup "farm-group"
├─ OrchestrationID (UUID: "550e8400-...")
├─ Manager (lifecycle control)
├─ RoutineName (which routine to execute)
├─ AvailableInstances ([1, 2, 3, 4, 5])
├─ AccountPool (execution-specific pool instance)
├─ InitialAccountCount (for progress monitoring)
└─ ActiveBots (currently running)
├─ Bot instance 1 → Emulator Instance 1
├─ Bot instance 2 → Emulator Instance 2
└─ Bot instance N → Emulator Instance N
- Orchestrator: Manages multiple independent bot groups
- BotGroup: Set of bots running same routine with same account pool
- Each group gets a unique OrchestrationID (UUID) for execution isolation
- Tracks InitialAccountCount for progress monitoring
- Bot Instance: Single bot running on specific emulator
- Emulator Instance: MuMu emulator (mapped 1:1 to bot instance)
Each bot group receives a unique UUID on creation:
- Isolates execution contexts - prevents stale records from old runs affecting new groups
- Tracks routine executions -
routine_executionstable includesorchestration_id - Manages account checkouts - database tracks which orchestration has which account
- Enables multi-tenancy - multiple groups can run same routine without conflicts
- Create Group: Generate unique orchestration ID, create manager
- Set Account Pool: Create execution-specific pool instance from definition, log initial count
- Validate: Check routine exists and templates are available
- Allocate: Reserve emulator instances
- Launch: For each bot - create, initialize, launch (staggered)
- Monitor: Track bot status and account progress
- Shutdown: Release all account checkouts for this orchestration
- Handle Failures: Per restart policy
Location: internal/accountpool/unified_pool.go
Account pools operate at two distinct levels:
-
Pool Definitions (YAML files): Shared templates defining how to query accounts
- Multiple orchestrations can use the same pool definition
- Stored in
pools/directory - Managed by
PoolManager
-
Execution-Specific Pools: Per-orchestration queue instances
- Each bot group creates its own pool instance from a definition
- Independent queues prevent cross-orchestration interference
- Tracked via
InitialAccountCountfor progress monitoring
A pool combines 4 account sources:
- SQL Queries:
SELECT device_account, device_password, ... - Manual Include: Specific account IDs to add
- Watched Paths: Folders to scan for XML imports
- Exclude List: Accounts to remove
Query results → Include manual → Watched paths → Exclude
Pool Definition (YAML)
↓
Orchestration creates execution-specific pool
↓
Available → GetNext() → [Database Checkout Check] → In Use → [Finalize] → Terminal State
↓ │
Already checked out? ├─ CompleteAccount → Completed (REMOVED + released)
→ Defer & retry ├─ MarkAccountFailed → Failed (REMOVED + released)
↓ └─ ReturnAccount → Available (BACK + released)
Checkout successful
→ Inject into emulator
Important:
- Accounts do NOT automatically return to the pool. Routines must explicitly call one of the finalization actions.
- Each bot group execution has a unique
orchestration_id(UUID) to isolate execution contexts. - Database checkout system prevents duplicate injections across orchestrations.
Purpose: Global mutex preventing simultaneous account injection across multiple orchestrations.
Checkout Columns (accounts table):
checked_out_to_orchestration: UUID of bot group using this accountchecked_out_to_instance: Emulator instance numberchecked_out_at: Timestamp of checkout
Workflow:
GetNext()retrieves account from execution-specific pool queueCheckoutAccount()atomically checks database:- If already checked out to different orchestration → defer & retry next account
- If available or checked out to same orchestration → proceed
- Account injected into emulator
- On completion/failure/return →
ReleaseAccount()clears orchestration ID - On group shutdown →
ReleaseAllAccountsForOrchestration()cleanup
Stale Checkout Detection:
- Checkouts older than 10 minutes are considered stale and can be reclaimed
- Handles ungraceful shutdowns and crashed routines
GetNext(): Get next available account from channel, mark as InUseMarkUsed(): Mark complete/failed with stats, REMOVE from circulationMarkFailed(): Permanently fail account, REMOVE from circulation (unless retry enabled and under max failures)Return(): Put back into available channel for retry (only if explicitly called)ListAccounts(): Get all accountsGetStats(): Summary statistics (includesInitialAccountCountfor progress)
Optional periodic refresh (e.g., every 60 seconds) to reload accounts from sources.
Location: internal/database/models.go
- Device login: email/password
- Resources: shinedust, hourglasses, pack points
- Statistics: packs opened, level, wonder picks
- Timestamps: created, last used, stamina recovery
- Metadata: file path, active status, banned status
Location: internal/accounts/injector.go
Process for injecting account data into the game:
- Force-stop Pokemon TCG app via ADB
- Push account XML to
/sdcard/deviceAccount.xml - Copy to game data:
/data/data/jp.pokemon.pokemontcgp/shared_prefs/deviceAccount:.xml - Clean up temporary file
Location: internal/actions/account.go
Actions for managing accounts within routines:
InjectNextAccount: Get from pool, inject, track assignmentCompleteAccount: Mark complete with stats (packs opened, cards found, etc.)ReturnAccount: Put back for retryMarkAccountFailed: Permanently fail with reason
Location: internal/actions/routine.go
A routine is a YAML file defining a sequence of actions with optional error handlers (sentries).
routine_name: "Pack Opener"
description: "Opens packs and collects cards"
tags: ["farming", "packs"]
config:
- name: max_packs
type: int
default: 10
steps:
- action: click
template: open_pack_button
- action: sleep
duration: 2000
- action: repeat
count: ${max_packs}
actions:
- action: ifimagefound
template: pack_available
actions:
- action: click
template: open
sentries:
- routine: error_handling/popup_handler
frequency: 15
severity: medium
on_success: resume- YAML parsed into
Routinestruct - Steps unmarshaled via action registry (polymorphic)
- Each step validates
- Each step builds into
ActionBuilder - Result: Executable
ActionBuilderwith all steps
RoutineExecutorloads sentries- Registers sentries with global
SentryManager - Executes main routine steps sequentially
- Unregisters sentries on completion
Location: internal/actions/
type ActionStep interface {
Validate(ab *ActionBuilder) error // Build-time validation
Build(ab *ActionBuilder) *ActionBuilder // Compile to Step
}type Click struct {
X int `yaml:"x"`
Y int `yaml:"y"`
Template string `yaml:"template"` // Optional
}
func (c *Click) Validate(ab *ActionBuilder) error {
// Validate template exists at build-time
return nil
}
func (c *Click) Build(ab *ActionBuilder) *ActionBuilder {
step := Step{
name: "Click",
execute: func(bot BotInterface) error {
// Resolve coordinates
x, y := c.X, c.Y
if c.Template != "" {
result, _ := bot.CV().FindTemplate(c.Template, nil)
x, y = result.Location.X, result.Location.Y
}
// Execute click via ADB
return bot.ADB().Tap(x, y)
},
}
ab.steps = append(ab.steps, step)
return ab
}- Click, Swipe, Input, SendKey
- IfImageFound, WhileImageFound, UntilImageFound, WaitForImage
- If, While, Until, Repeat, Break
- SetVariable, Increment, Decrement
- InjectNextAccount, CompleteAccount, ReturnAccount
- UpdateAccountField, GetAccountField
- SentryHalt, SentryResume
- Sleep, Comment
Variables can be substituted at runtime:
- action: repeat
count: ${max_packs} # Substituted from configLocation:
Background routines that monitor for errors while the main routine runs.
sentries:
- routine: error_handling/popup_handler
frequency: 15 # Poll every 15 seconds
severity: low
on_success: resume # If handler succeeds, resume main
on_failure: stop # If handler fails, stop botRoutine A starts → Register sentry X (refcount=1, engine starts)
Routine B starts → Register sentry X (refcount=2, engine continues)
Routine B ends → Unregister sentry X (refcount=1, still running)
Routine A ends → Unregister sentry X (refcount=0, engine stops)
- Deduplication: Same sentry not run multiple times
- Reference Counting: Cleanup when last user unregisters
- Frequency Optimization: Uses fastest frequency if multiple requesters
- Routine Control: Can pause/stop main routine via
RoutineController
Each sentry runs in a separate goroutine:
- Polls at configured frequency
- Executes sentry routine
- Takes configured action if condition matches
- Stops when reference count reaches zero
1. App Startup
├─ Load Settings.ini
├─ Create TemplateRegistry (load all YAML templates)
├─ Create RoutineRegistry (load all YAML routines)
├─ Create PoolManager (load all pool definitions)
└─ Create Orchestrator (pass shared registries)
2. User Launches Bot Group
├─ Orchestrator validates routine exists
├─ Allocate emulator instances
└─ For each bot (staggered launch):
├─ Create Bot instance
├─ Bot.Initialize() (ADB, CV, inject registries)
└─ Launch bot.ExecuteRoutine() in goroutine
3. Bot Executes Routine
├─ Get routine from RoutineRegistry
├─ Initialize config variables
├─ Create RoutineExecutor with sentries
├─ SentryManager.Register(sentries)
│ └─ SentryEngine starts in background
│ └─ Each sentry polls on its frequency
├─ ActionBuilder.Execute(bot)
│ └─ For each step in sequence:
│ ├─ Execute step function
│ ├─ Handle errors via recovery
│ ├─ Check pause/stop from sentries
│ └─ Apply step timeout if configured
├─ SentryManager.Unregister(sentries)
│ └─ SentryEngine stops (if refcount=0)
└─ Account marked complete/failed
4. Routine Completion
├─ All steps executed
├─ Account status finalized:
│ ├─ CompleteAccount: Marks complete/failed, REMOVES from pool
│ ├─ ReturnAccount: Returns to pool for reuse
│ └─ MarkAccountFailed: Permanently fails account
├─ Bot status updated
└─ Orchestrator may restart per policy
The architecture employs several well-known design patterns:
- Builder Pattern: ActionBuilder separates validation from execution
- Registry Pattern: Centralized lookup (Templates, Routines, Actions)
- Polymorphic Unmarshaling: Use reflection + registry for YAML deserialization
- Dependency Injection: BotInterface breaks circular dependencies
- Reference Counting: Sentry lifecycle management
- Factory Pattern: Orchestrator creates bot instances
- Observer Pattern: Error monitoring via sentries
- Composable: Actions combine for complex behaviors
- Testable: Clear interfaces, dependency injection
- Scalable: Multiple bots can run in parallel
- Flexible: YAML-based routines (no recompilation needed)
- Robust: Sentries, error monitoring, health checks
- Maintainable: Clear separation of concerns
| Component | File | Purpose |
|---|---|---|
| CV Service | internal/cv/service.go | Screenshot + template matching |
| Template Registry | pkg/templates/registry.go | Template YAML loading |
| Routine Registry | internal/actions/routine_registry.go | Routine discovery & loading |
| Action Registry | internal/actions/registry.go | Action type mapping |
| ActionBuilder | internal/actions/builder.go | Action compilation |
| Routine YAML | internal/actions/routine.go | YAML parsing + polymorphism |
| Unified Pool | internal/accountpool/unified_pool.go | Account pool implementation |
| Orchestrator | internal/bot/orchestrator.go | Multi-bot coordination |
| Sentry Manager | internal/actions/sentry_manager.go | Lifecycle management |
| Sentry Engine | internal/actions/sentry_engine.go | Background execution |
| Account Actions | internal/actions/account.go | Pool interaction actions |
| Injector | internal/accounts/injector.go | ADB-based XML injection |
This section provides comprehensive documentation for all available actions in the system.
Perform a tap at specific coordinates.
- action: click
x: 500
y: 300Parameters:
x(int, required): X coordinatey(int, required): Y coordinate
Perform a swipe gesture between two points.
- action: swipe
x1: 100
y1: 500
x2: 400
y2: 500
duration: 300Parameters:
x1,y1(int, required): Starting coordinatesx2,y2(int, required): Ending coordinatesduration(int, optional): Swipe duration in milliseconds (default: 300)
Input text into a field.
- action: input
text: "Hello World"Parameters:
text(string, required): Text to input
Send a key press event.
- action: send_key
key: "KEYCODE_BACK"Parameters:
key(string, required): Android keycode (e.g., KEYCODE_BACK, KEYCODE_HOME)
Find a template on screen and save coordinates.
- action: findimage
template: button_name
save_x: x_coord
save_y: y_coord
threshold: 0.85Parameters:
template(string, required): Template name from registrysave_x(string, optional): Variable name to store X coordinatesave_y(string, optional): Variable name to store Y coordinatethreshold(float, optional): Override template's thresholdregion(object, optional): Search region{x1, y1, x2, y2}
Click template if found (single check).
- action: clickifimagefound
template: button_name
offset_x: 10
offset_y: 20Parameters:
template(string, required): Template nameoffset_x,offset_y(int, optional): Click offset from template centerthreshold(float, optional): Override thresholdregion(object, optional): Search region
Click coordinates if template NOT found.
- action: clickifimagenotfound
template: popup
x: 500
y: 300Parameters:
template(string, required): Template to check for absencex,y(int, required): Coordinates to click if not foundthreshold(float, optional): Override threshold
Wait until template appears (with timeout).
- action: waitforimage
template: loading_complete
timeout: 30000
check_interval: 500Parameters:
template(string, required): Template to wait fortimeout(int, optional): Timeout in milliseconds (default: 30000)check_interval(int, optional): Check interval in ms (default: 500)threshold(float, optional): Override threshold
Execute actions based on structured conditions (supports elseif and else).
- action: if
condition:
type: variable_greater_than
variable: level
value: "10"
then:
- action: click
x: 100
y: 200
elseif:
- condition:
type: variable_equals
variable: level
value: "5"
then:
- action: click
x: 300
y: 400
else:
- action: sleep
duration: 1000Parameters:
condition(object, required): Structured condition (see Boolean Conditions section)then(list, required): Actions to execute if condition is trueelseif(list, optional): Additional condition brancheselse(list, optional): Actions if no conditions match
Execute actions if template is found.
- action: ifimagefound
template: popup_close
actions:
- action: click
template: popup_closeParameters:
template(string, required): Template to checkactions(list, required): Actions to execute if foundthreshold(float, optional): Override thresholdregion(object, optional): Search region
Execute actions if template is NOT found.
- action: ifimagenotfound
template: loading_screen
actions:
- action: click
x: 500
y: 300Parameters:
template(string, required): Template to check for absenceactions(list, required): Actions to execute if not found
Execute actions if ANY of the templates are found.
- action: ifanyimagesfound
templates:
- popup1
- popup2
- popup3
actions:
- action: click
x: 500
y: 300Parameters:
templates(list, required): List of template namesactions(list, required): Actions to execute if any found
Execute actions if ALL templates are found.
- action: ifallimagesfound
templates:
- icon1
- icon2
actions:
- action: click
x: 500
y: 300Parameters:
templates(list, required): List of template namesactions(list, required): Actions to execute if all found
Execute actions if NONE of the templates are found.
- action: ifnoimagesfound
templates:
- error1
- error2
actions:
- action: click
x: 500
y: 300Parameters:
templates(list, required): List of template namesactions(list, required): Actions to execute if none found
Repeat actions a fixed number of times.
- action: repeat
iterations: 5
actions:
- action: click
x: 500
y: 300
- action: sleep
duration: 1000Parameters:
iterations(int, required): Number of times to repeat (supports${variable})actions(list, required): Actions to repeat
Repeat actions while structured condition is true.
- action: while
condition:
type: variable_less_than
variable: counter
value: "10"
max_attempts: 100
actions:
- action: click
x: 500
y: 300
- action: increment
variable: counterParameters:
condition(object, required): Structured condition (see Boolean Conditions section)max_attempts(int, optional): Safety limit (0 = infinite)actions(list, required): Actions to repeat
Repeat actions while template is visible.
- action: whileimagefound
template: continue_button
max_iterations: 50
actions:
- action: click
template: continue_button
- action: sleep
duration: 2000Parameters:
template(string, required): Template to checkmax_iterations(int, optional): Safety limit (default: 1000)actions(list, required): Actions to repeatthreshold(float, optional): Override threshold
Repeat while ANY template is visible.
- action: whileanyimagesfound
templates:
- loading1
- loading2
max_iterations: 100
actions:
- action: sleep
duration: 500Parameters:
templates(list, required): List of template namesmax_iterations(int, optional): Safety limitactions(list, required): Actions to repeat
Repeat actions until structured condition becomes true.
- action: until
condition:
type: variable_equals
variable: success
value: "true"
max_attempts: 50
actions:
- action: click
x: 500
y: 300Parameters:
condition(object, required): Structured condition (see Boolean Conditions section)max_attempts(int, optional): Safety limit (0 = infinite)actions(list, required): Actions to repeat
Repeat actions until template appears.
- action: untilimagefound
template: success_screen
max_iterations: 30
actions:
- action: click
x: 500
y: 300
- action: sleep
duration: 1000Parameters:
template(string, required): Template to wait formax_iterations(int, optional): Safety limit (default: 1000)actions(list, required): Actions to repeatthreshold(float, optional): Override threshold
Repeat until ANY template appears.
- action: untilanyimagesfound
templates:
- result1
- result2
max_iterations: 50
actions:
- action: click
x: 500
y: 300
- action: sleep
duration: 500Parameters:
templates(list, required): List of template namesmax_iterations(int, optional): Safety limitactions(list, required): Actions to repeat
Exit current loop early.
- action: repeat
iterations: 100
actions:
- action: ifimagefound
template: complete
actions:
- action: breakParameters: None
Set a variable to a value.
- action: setvariable
variable: counter
value: "10"Parameters:
variable(string, required): Variable namevalue(string, required): Value to set (supports interpolation)
Get a variable value (primarily for debugging).
- action: getvariable
variable: counterParameters:
variable(string, required): Variable name
Increment a numeric variable.
- action: increment
variable: counter
amount: 1Parameters:
variable(string, required): Variable nameamount(int, optional): Increment amount (default: 1)
Decrement a numeric variable.
- action: decrement
variable: counter
amount: 1Parameters:
variable(string, required): Variable nameamount(int, optional): Decrement amount (default: 1)
Get and inject the next account from the pool.
- action: injectnextaccount
timeout: 30000
save_result: account_id
on_no_accounts: stopParameters:
timeout(int, optional): Wait timeout in ms (default: 30000)save_result(string, optional): Variable to store account IDon_no_accounts(string, optional): Action if pool empty: "wait", "stop", "continue" (default: "stop")
Mark current account as completed with stats.
- action: completeaccount
packs_opened: ${packs_count}
cards_found: ${cards_count}
shinedust_gained: ${dust_amount}Parameters:
packs_opened(int, optional): Number of packs openedcards_found(int, optional): Number of cards foundshinedust_gained(int, optional): Shinedust gainedhourglasses_used(int, optional): Hourglasses usedpack_points_used(int, optional): Pack points used- All parameters support variable interpolation
Return current account to pool without completing.
- action: returnaccount
reason: "timeout"Parameters:
reason(string, optional): Reason for return
Mark current account as failed.
- action: markaccountfailed
reason: "banned"Parameters:
reason(string, required): Failure reason
Update a specific field in the account database.
- action: updateaccountfield
field: level
value: ${current_level}Parameters:
field(string, required): Field name (e.g., "level", "shinedust")value(string, required): New value (supports interpolation)
Increment a numeric field in the account database.
- action: incrementaccountfield
field: packs_opened
amount: 1Parameters:
field(string, required): Field nameamount(int, optional): Increment amount (default: 1)
Get a field value from account database.
- action: getaccountfield
field: level
save_to: current_levelParameters:
field(string, required): Field namesave_to(string, required): Variable to store result
Update metrics for routine execution.
- action: updateroutinemetrics
routine_name: ${routine_name}
success: true
duration: ${execution_time}Parameters:
routine_name(string, required): Routine identifiersuccess(bool, required): Whether execution succeededduration(int, optional): Execution time in milliseconds
Execute another routine by name.
- action: runroutine
routine: error_handling/popup_closerParameters:
routine(string, required): Routine name/path
Temporarily halt all active sentries.
- action: sentryhaltParameters: None
Use Case: During critical operations where sentry interruption would cause issues.
Resume all halted sentries.
- action: sentryresumeParameters: None
Wait for a fixed duration.
- action: sleep
duration: 2000Parameters:
duration(int, required): Duration in milliseconds (supports${variable})
Alias for sleep.
- action: delay
duration: 1000Parameters:
duration(int, required): Duration in milliseconds
The If, While, and Until actions support sophisticated structured conditions (not string expressions).
Check if a template is visible.
condition:
type: image_exists
template: button_name
threshold: 0.85
region:
x1: 100
y1: 100
x2: 500
y2: 500Check if a template is NOT visible.
condition:
type: image_not_exists
template: loading_screenCheck if a variable equals a value.
condition:
type: variable_equals
variable: counter
value: "10"Check if a variable does not equal a value.
condition:
type: variable_not_equals
variable: status
value: "complete"Numeric comparison: variable > value.
condition:
type: variable_greater_than
variable: level
value: "5"Numeric comparison: variable < value.
condition:
type: variable_less_than
variable: attempts
value: "10"Numeric comparison: variable >= value.
condition:
type: variable_greater_than_or_equal
variable: score
value: "100"Numeric comparison: variable <= value.
condition:
type: variable_less_than_or_equal
variable: health
value: "50"Check if variable contains substring.
condition:
type: variable_contains
variable: message
substring: "error"Check if variable starts with prefix.
condition:
type: variable_starts_with
variable: filename
prefix: "output_"Check if variable ends with suffix.
condition:
type: variable_ends_with
variable: filename
suffix: ".txt"All conditions must be true.
condition:
type: all
conditions:
- type: variable_greater_than
variable: level
value: "5"
- type: image_exists
template: ready_buttonAt least one condition must be true.
condition:
type: any
conditions:
- type: image_exists
template: error1
- type: image_exists
template: error2Negate a condition.
condition:
type: not
condition:
type: image_exists
template: loadingNone of the conditions can be true.
condition:
type: none
conditions:
- type: image_exists
template: error1
- type: image_exists
template: error2- action: if
condition:
type: all
conditions:
- type: variable_greater_than
variable: level
value: "10"
- type: any
conditions:
- type: image_exists
template: bonus_available
- type: variable_equals
variable: bonus_mode
value: "enabled"
then:
- action: click
template: bonus_button
elseif:
- condition:
type: variable_equals
variable: level
value: "5"
then:
- action: click
x: 500
y: 300
else:
- action: sleep
duration: 1000All string and numeric parameters support variable interpolation using ${variable_name} syntax:
- action: repeat
iterations: ${max_loops}
actions:
- action: click
x: ${button_x}
y: ${button_y}
- action: sleep
duration: ${delay_ms}Variables can come from:
- Routine config: Defined in routine's
configsection - Runtime variables: Set via
setvariable,increment,decrement - Action results: Saved via
save_result,save_to,save_x,save_yparameters
This is a sophisticated, well-architected system for game automation with enterprise-grade patterns and clear separation of concerns.