# Triggers System

This page covers how to create custom trigger types and requirement types that integrate with Spark's systems.

## Creating Custom Trigger Types

A trigger type defines an action that can be configured in the Spark Editor and executed at runtime. To create one, you need to understand the trigger system's architecture.

### Trigger Type Structure

Each trigger type is a class that:

1. Defines its configurable fields (shown in the Spark Editor)
2. Implements execution logic (what happens when the trigger fires)
3. Registers itself with the Triggers plugin

Here is the pattern, based on how built-in trigger types work:

```csharp
using UnityEngine;

[System.Serializable]
public class GiveReputationTriggerType
{
    [DatabaseEntryDropdown(typeof(FactionEntry))]
    [SerializeField] private string factionId;

    [SerializeField] private int amount = 10;

    [DisplayNameTooltip("Source", "What caused this reputation change.")]
    [SerializeField] private string source = "trigger";

    public void Execute(string characterId)
    {
        Spark.Network?.ExecuteCommand(new ModifyReputationCommand
        {
            CharacterId = characterId,
            FactionId = factionId,
            Amount = amount,
            Source = source
        });
    }
}
```

Key points:

* Use `[SerializeField]` for fields the designer configures in the editor.
* Use Spark attributes (`[DatabaseEntryDropdown]`, `[ConditionalField]`, etc.) for a good editor experience.
* Execute actions through commands, not directly. This ensures networking compatibility.
* Keep the trigger focused on a single action.

### Trigger Attributes

Use these attributes on trigger type fields:

* `[TriggerRefresh]`: Marks a field that should refresh the trigger UI when changed.
* `[HorizontalRuleTriggers]`: Adds a visual separator line before the field.

## Creating Custom Requirement Types

A requirement type defines a condition that can be checked at runtime.

### Requirement Type Structure

```csharp
using UnityEngine;

[System.Serializable]
public class FactionReputationRequirementType
{
    [DatabaseEntryDropdown(typeof(FactionEntry))]
    [SerializeField] private string factionId;

    [SerializeField] private ComparisonType comparison = ComparisonType.GreaterThanOrEqual;

    [SerializeField] private int requiredAmount = 0;

    public bool Check(string characterId)
    {
        if (!SparkEntityRegistry.TryGetEntity(characterId, out SparkEntity entity))
            return false;

        var tracker = entity.GetSparkComponent<FactionTrackerEntity>();
        if (tracker == null)
            return false;

        int current = tracker.GetReputation(factionId);

        return comparison switch
        {
            ComparisonType.Equal => current == requiredAmount,
            ComparisonType.NotEqual => current != requiredAmount,
            ComparisonType.GreaterThan => current > requiredAmount,
            ComparisonType.GreaterThanOrEqual => current >= requiredAmount,
            ComparisonType.LessThan => current < requiredAmount,
            ComparisonType.LessThanOrEqual => current <= requiredAmount,
            _ => false
        };
    }
}
```

Key points:

* Use `ComparisonType` for numeric comparisons. Spark provides this enum.
* Return `bool` from the check method.
* Always handle null cases gracefully (entity not found, component missing).
* Use `[HorizontalRuleChecks]` attribute for visual separators in the editor.

## Registration

Trigger types and requirement types are discovered by the Triggers and Requirements plugins through reflection and assembly scanning. Place them in an assembly that references the Triggers or Requirements plugin assembly, and they will be picked up automatically.

## Best Practices

* Name trigger types as `{Action}TriggerType` (e.g., `GiveReputationTriggerType`).
* Name requirement types as `{Condition}RequirementType` (e.g., `FactionReputationRequirementType`).
* Always execute state changes through commands in triggers.
* Always validate all inputs in requirements (null checks, entity checks).
* Use Spark's custom attributes for a polished editor experience.
* Keep triggers and requirements stateless. They should work purely from their serialized fields and the current game state.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.sparkframework.dev/documentation/developer-guide/core-systems/triggers-system.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
