Skip to content

Script Basics

This guide covers the fundamental concepts and structure of scripts in Arcade Tiled RPG.

What is a Script?

A script is a JSON object that defines:

  1. When to trigger (event type)
  2. If it should run (conditions)
  3. What to do (action sequence)

Script Structure

Every script follows this basic structure:

{
  "script_name": {
    "scene": "village",
    "trigger": {
      "event": "npc_interacted",
      "npc": "merchant"
    },
    "run_once": true,
    "actions": [
      {
        "type": "dialog",
        "speaker": "Merchant",
        "text": ["Hello, traveler!"]
      },
      {
        "type": "play_sfx",
        "file": "greeting.wav"
      }
    ]
  }
}

Script Components

Script Name ("script_name")

  • Unique identifier for the script
  • Use descriptive names like "merchant_first_meeting" or "quest_start"

Scene ("scene")

  • Optional: Which scene/map this script runs in
  • If specified, script only runs in that scene (scene-specific)
  • If omitted, script can run in any scene (global script)
  • Example: "scene": "village"

Trigger ("trigger")

  • Required: Defines what event activates this script
  • Contains event type and conditions
  • Example: {"event": "npc_interacted", "npc": "merchant"}

Run Once ("run_once")

  • Optional: If true, script only executes once then disables
  • Default: false (script can run multiple times)
  • Use for one-time events like first meetings or story moments

Actions ("actions")

  • Required: Array of actions to execute when script triggers
  • Actions run sequentially in order
  • Each action has a "type" and type-specific parameters

File Location

Scripts are organized by scene/map in the assets/scripts/ directory:

assets/scripts/
  ├── village_scripts.json
  ├── forest_scripts.json
  └── castle_scripts.json

File Organization Tips

You can organize scripts by:

  • Scene/Map: One file per location (recommended)
  • Feature: Main quest, side quests, NPCs, events
  • Quest Line: Group related story scripts together

Example organization:

assets/scripts/
  ├── village_main_quest.json
  ├── village_side_quests.json
  ├── village_npcs.json
  └── village_events.json

Loading Scripts

All scripts are automatically loaded globally when the ScriptPlugin initializes during plugin setup. The plugin scans the assets/scripts/ directory for all files matching the pattern *_scripts.json and loads them into a single registry.

Global Loading:

# Scripts are loaded during setup
script_plugin = ScriptPlugin()
script_plugin.setup(context)  # Loads all scripts from scripts directory

Key Points:

  • All scripts from all files are loaded at once
  • Scripts are available for condition checking across all scenes
  • The scene field in each script controls when it can execute
  • Scripts are reloaded on reset (new game or load game)

You don't need to manually load scripts - the plugin handles this automatically.

How Scripts Execute

  1. Event Occurs: Player interacts with NPC, closes dialog, etc.
  2. Event Handling: EventBus publishes event to all subscribers
  3. Matching: Script plugin finds all scripts with matching event type in trigger
  4. Filtering: Checks if trigger fields match, scene matches, and conditions are met
  5. Execution: Runs the actions array sequentially
  6. Completion: Emits script_complete event when finished

Script Properties

scene

Type: string (optional)

Only run the script in a specific scene/map.

{
  "village_only": {
    "scene": "village",
    "trigger": {
      "event": "dialog_closed",
      "npc": "merchant"
    },
    "actions": []
  }
}

Use Cases:

  • Scene-specific behaviors
  • Map-dependent events
  • Location-based triggers

run_once

Type: boolean (default: false)

Execute the script only once, then disable it.

{
  "first_meeting": {
    "scene": "village",
    "trigger": {
      "event": "npc_interacted",
      "npc": "merchant"
    },
    "run_once": true,
    "actions": []
  }
}

Use Cases:

  • First-time conversations
  • One-time item pickups
  • Story events that shouldn't repeat

Best Practices

1. Use Descriptive Names

// Bad
{"s1": {...}}

// Good
{"merchant_first_meeting": {...}}

2. Keep Scripts Focused

Break long action sequences into multiple scripts using script_complete:

// Bad - Too many unrelated actions
{
  "actions": [
    {"type": "dialog", ...},
    {"type": "move_npc", ...},
    {"type": "play_music", ...},
    {"type": "reveal_npcs", ...}
    // 20 more actions...
  ]
}

// Good - Break into multiple scripts
{
  "part1": {
    "trigger": {...},
    "actions": [...]
  },
  "part2": {
    "trigger": {
      "event": "script_complete",
      "script": "part1"
    },
    "actions": [...]
  }
}

3. Use run_once for Story Events

{
  "important_story_moment": {
    "scene": "village",
    "trigger": {...},
    "run_once": true,  // Prevents repeating
    "actions": [...]
  }
}

4. Use Scene Property for Map-Specific Scripts

{
  "village_welcome": {
    "scene": "village",  // Only runs in village
    "trigger": {
      "event": "npc_interacted",
      "npc": "elder"
    },
    "actions": [...]
  },
  "global_item_pickup": {
    // No scene property - runs in ANY scene
    "trigger": {
      "event": "item_acquired"
    },
    "actions": [
      {"type": "play_sfx", "file": "pickup.wav"}
    ]
  }
}

5. Use Trigger Fields Wisely

// Specific trigger conditions prevent unwanted triggers
{
  "my_script": {
    "scene": "village",
    "trigger": {
      "event": "npc_interacted",
      "npc": "merchant",
      "dialog_level": 0
    },
    "actions": [...]
  }
}

6. Document Complex Scripts

{
  "complex_cutscene": {
    // This script triggers the main story event where the king reveals
    // the ancient prophecy. Requires player to have talked to king 5 times.
    "scene": "throne_room",
    "trigger": {
      "event": "npc_interacted",
      "npc": "king",
      "dialog_level": 5
    },
    "actions": [...]
  }
}

Debugging Scripts

Check Script Loading

Enable logging to see script load messages:

import logging
logging.basicConfig(level=logging.DEBUG)

Common Issues

Script not triggering:

  • Check event_type matches the actual event
  • Verify all conditions are met
  • Ensure scene name matches if scene property is set
  • Check if run_once script already executed

Actions not executing:

  • Verify action type spelling
  • Check params match expected format
  • Look for console errors
  • Ensure required NPCs/objects exist

NPCs not moving:

  • Verify waypoint exists in Tiled map
  • Check pathfinding can find a route
  • Ensure NPC isn't already moving

Dialogs not showing:

  • Check dialog JSON exists and is valid
  • Verify npc_name matches dialog file
  • Ensure dialog level exists in JSON

Performance Tips

  1. Limit concurrent scripts: Too many active scripts can impact performance
  2. Use run_once: Prevents unnecessary condition checking
  3. Avoid tight loops: Don't create scripts that trigger each other rapidly
  4. Clean up references: Remove event listeners when scenes unload

Next Steps

  • Learn about Event Types to understand what can trigger your scripts
  • Explore Conditions to control when scripts execute
  • Browse Actions to see what your scripts can do