# Custom Conditions

A **Condition** derives from `Condition` and implements a synchronous method that returns `bool`. The editor discovers the compiled type and adds it to Conditions lists.

## A minimal Condition

This Condition compares a Game Object Signal's tag with a String Signal:

```cs
using System;
using UnityEngine;
using VisualScript.Icons;
using VisualScript.Runtime;

[Title("Game Object Tag")]
[Description("Compares a Game Object tag with another value")]
[Category("Game Object/Tag")]

[Parameter("Game Object", "The Game Object targeted")]
[Parameter("Tag", "The value to compare against")]

[Image(typeof(IconTag), ColorTheme.Type.TextLight)]

[Serializable]
public class ConditionMyGameObjectTag : Condition
{
    [SerializeField] private GetGameObject m_GameObject = new GetGameObject();
    [SerializeField] private GetString m_Tag = new GetString();

    protected override string GetTitle(GameObject source) => $"{this.m_GameObject} Tag = {this.m_Tag}";

    protected override bool Run(Args args)
    {
        GameObject gameObject = this.m_GameObject.Get(args);
        string tag = this.m_Tag.Get(args);

        return gameObject != null && gameObject.CompareTag(tag);
    }
}
```

`Run` returns `true` when the resolved object exists and its tag matches `m_Tag`. The attributes, serialized Signals, and title follow the same shape as an [Instruction](instructions.md), with a synchronous `bool Run(Args)` contract.

## Conditions must be pure

The caller evaluates `Run` whenever it needs an answer. This can happen several times per frame, including every frame inside **While** or **Wait Until**.

!!! warning "Never change state in a Condition"
    A Condition that increments a counter, spawns an object, or writes a variable produces results based on evaluation frequency. The caller controls that frequency, so the resulting state is unpredictable.

    Use an [Instruction](instructions.md) for operations that change state.

The inversion toggle negates the result after calling `Run`. It doesn't prevent any side effects inside `Run`.

## Keep it cheap

Because Conditions can be evaluated every frame, choose an operation whose cost fits that frequency:

| Cheap | Expensive |
| :--- | :--- |
| Comparing values | Searching the scene |
| Reading a component | Physics queries |
| Reading a variable | Iterating a large collection |
| String equality | Allocating |

Use an expensive Condition only when the check requires it. Add a `[Note]` that identifies the cost so designers avoid evaluating it every frame through **Wait Until**.

## Null safety

Signals resolve to `null` when an object was destroyed, a variable was never set, or a lookup found nothing.

A Condition should treat that as `false` rather than throwing. Guard the resolved value before running the remaining check, which is omitted here:

```cs
protected override bool Run(Args args)
{
    GameObject gameObject = this.m_GameObject.Get(args);
    if (gameObject == null) return false;

    // …
}
```

The null guard returns a valid Condition result and keeps the containing Event running.

## Condition or Bool Signal?

Both return a boolean result. Choose based on where designers need to use the check:

| Write a | When |
| :--- | :--- |
| **Bool Signal** | The value is useful anywhere a boolean is — inside other Signals, as a field on a component, stored in a variable. |
| **Condition** | The check reads more clearly as a guard in a Conditions list. |

Prefer the **Signal** when both forms read well. A Bool Signal composes, can be stored, supports bindings, and still works as a guard through the Condition that wraps it.

## Checklist

- `[Serializable]`, derived from `Condition`.
- `Run` is pure — no state changes anywhere.
- `null` results in `false`, not an exception.
- Evaluation cost fits the expected frequency, with expensive operations documented in `[Note]`.
- `GetTitle` reads as a statement: *Target has tag Enemy*.

## Where to go next

- **[Custom Instructions](instructions.md)** — perform work instead of checking state.
- **[Custom Signals](signals.md)** — provide a composable boolean value.
- **[Args](../args.md)** — follow the context `Run` receives.
